

A Week with Mozilla's Rust - lengads
http://relistan.com/a-week-with-mozilla-rust/

======
klibertp
The example of match usage is really poor. From the looks of it there is no
"pattern matching" going on at all here. I don't know the syntax, but even
something like this would be a better demonstration:

    
    
        let computed_key = match (key.len() > self.block_size, key.len() < self.block_size) {
            (true, false) => self.zero_pad(self.hash(key).digest),
            (false, true) => self.zero_pad(key),
            (false, false) => key
        }
    

At least there is some matching here, unlike in the original example. But in
real world this should be if..else if..else statement, not match - the latter
being used makes no sense if there is no matching going on. In Erlang there is
an if statement, which is a 'case' (equivalent of match here) but with matches
taken out and only guards allowed - that's what would fit here, but I doubt
Rust has something like this.

Also, does the compiler complain about my example above being not exhaustive?
I think in OCaml it would, which is sometimes nice.

~~~
catnaroek
As noted by masklinn, the compiler will complain about the non-exhaustive
match. Stuff like this makes me want a dependently typed language for
practical programming, in which I can express the concept of "this case ought
to be impossible", and convince the compiler by supplying a proof. Also, this
would eliminate the false dichotomy between "fast, unchecked, unsafe array
indexing" and "slow, checked, safe array indexing", which would be a huge win
for safe systems programming.

~~~
Locke1689
I assume you're familiar with ATS? What don't you like about it?

~~~
rdtsc
I am not the original poster but I'll respond to this one:

I am familiar with ATS and I don't like that I am only familiar with it from
the Language Shootout contest website. I haven't heard of it used in
production, no blogs, no news on HN.

It is a bad excuse and rather sad but my main charge against it is that it is
not popular enough.

~~~
doublec
I agree not much is heard about it. I blog about it a fair amount on [1].
There's also /r/ats [2]. I use it in production. The backend of my bitcoin
mining pool [3] is written in ATS and has about 1% of the total bitcoin mining
capacity and has been operating for a couple of years. The front end of the
pool is written in Ur/Web.

[1] [http://bluishcoder.co.nz/tags/ats/](http://bluishcoder.co.nz/tags/ats/)
[2] [http://www.reddit.com/r/ATS/](http://www.reddit.com/r/ATS/) [3]
[http://mmpool.bitparking.com](http://mmpool.bitparking.com)

------
Goosey
I enjoyed the article as I haven't been exposed to much Rust yet, but I was
disappointed that the intro didn't match the content

The second sentence:

> I want a language where I can be much more productive than in C: one in
> which I do not fear the correctness of my memory management, and don’t have
> to go through major gyrations to write concurrent code.

And we see no explicit demonstrations of the memory management and no
demonstrations at all of the concurrency model. It feels like the author had a
more fleshed out post in mind, but either decided it was running too long or
got bored before reaching the conclusion. :\

~~~
jkbyc
I agree, the actual content doesn't match the introduction so well.

I've been looking into Rust during the past few days and I must say I got
stuck on the memory model - all the different pointers and their interaction
with ownership and mutability, closures capturing their environment (variables
outside the closure in the scope where the closure is defined), reference
binding, and then things like std::Cell which on the one hand seems to be an
alternative to std::Option but on the other hand it's using some unsafe
operations in its implementation to change mutability or something... It's
quite confusing and it stopped me from writing a simple example application I
wanted to write because I wanted to understand what's going on a bit better
first.

~~~
pcwalton
> all the different pointers

@ is going to sink into the library and will be deemphasized in the language
to help with this. That leaves only ~ (pointers) and & (references).

> closures capturing their environment (variables outside the closure in the
> scope where the closure is defined)

Right, this is one of the difficult pieces. This is going away as well in
favor of Java-like Runnables to make the variable capture easier to understand
(with macro sugar to make them just as convenient as closures). The closures
that remain will work just like the closures you know from other languages
regarding variable capture, and the Rust-specific stuff regarding variable
capture will be gone.

> std::Cell

Yeah, this needs to be better documented. Part of the problem is that we
haven't totally nailed down what Cell will be used for yet.

------
dkhenry
Of all the upcoming languages out there. I think rust is best positioned. The
fact that it is really the only contender that can preform the same role as C,
but it folds in lots of the language design theory of the past three decades
puts it in a league of its own.

~~~
catnaroek
Exactly! This is what makes Rust _exciting_ \- as opposed to yawnfests like Go
that merely provide a compiled, somewhat faster Python.

~~~
lucian1900
Go does have one interesting feature: CSP concurrency built in. Even this was
predated by Erlang, though.

~~~
buster
I was really a little bit disappointed to learn that go (touted for it's
goroutines) doesn't have actors, i would love to have the erlang style,
network aware actor model in a language i belief i could learn easily ;)
Without that, i don't see so much noveltly :( All in all i don't see how
goroutines can compare to the Erlang model at all (

------
lambda
That seems like a really bad example of pattern matching, as no pattern
matching is going on; it's just using the guard statements, and so could be
replaced with an if statement:

    
    
        let computed_key = if key.len() > self.block_size {
            self.zero_pad(self.hash(key).digest)
        } else if key.len() < self.block_size {
            self.zero_pad(key)
        } else {
            key
        }

~~~
scribu
So the last statement in a block for a matched if condition gets assigned to
the variable? That's pretty cool.

~~~
rybosome
Any language that emphasizes expressions over statements will have this
feature. Off the top of my head, that should include Haskell, Scala,
CoffeeScript, Ruby, Elixir, Clojure (hell, anything Lisp really)...

The idea is that while you may be able to traverse code-paths with side
effects in some of these languages, they encourage treating a line of code
(term used loosely, as an expression can span multiple lines) as a computable
value. It may take a bit of getting used to at first, but from my own
experience, it now feels weird and awkward when a language doesn't.

Reminds me of looking at a nasty language like MUMPS or something, where
persistence is built into the core language; statement-oriented languages tend
not to be composable.

------
gnur
I don't think it's fair to compare Rust to Go, while operating on nearly the
same level. They are targeting a very different crowd. Go has very clean
syntax, few reserved words and writes almost as easy as python. This makes go
a attractive language for programmers who have a history with languages like
php & python but also want more speed. Rust on the other hand has a more
complex syntax but allows you more control over memory, thus making it more
attractive for those with a history in C or C++. Go is a good language to
learn as your first compiled language, easy to write, easy to learn and a good
ratio between performance and effort. Rust is (or will be when it's stable) a
good language to learn when you have a history in C and you want memory & type
safety but still the control you are used to in C/C++.

------
reirob
I enjoyed the article very much. Please continue with your journey of
explaining Rust to programmers that are looking for new alternatives to C.

~~~
relistan
I really appreciate that feedback. Thanks!

------
chimeracoder
I don't want to turn this into a Go vs. Rust discussion, because the two
languages are very different and have very different goals.

However, I want to question the claim:

> Go is also not particularly friendly to interface to external libraries
> written in C

which doesn't seem to be explained anywhere in the article, and jars with my
understanding.

Go does play very well with C; cgo[0] makes this pretty straightforward.

Maybe there are specific things that the author is trying to do that they
found difficult in Cgo, but I would say that Go does play fairly nicely with
C; that was a design goal.

Here's a simple example of cgo in action:
[http://golang.org/doc/articles/c_go_cgo.html](http://golang.org/doc/articles/c_go_cgo.html).
As you can see, it's relatively straightforward and easy to use.

[0] [http://golang.org/cmd/cgo/](http://golang.org/cmd/cgo/)

~~~
acqq
Rust not having the garbage collection as far as I understand can be made to
produce routines that are part of C application. As far as I understand, by
design Go can't be a "nice" citizen in a C application, the Go routine will
bring with itself the whole city it lives in to your flat.

So Go applications are something like "compiled, fast Ruby or Python." As far
as I understand, Rust should theoretically be a way to write a piece of your
application (even mainly C application) in something that gives you a
different kind of expressibility. If there's need for that is another
question, specifically, I'd like to see some examples that would really
impress me. The examples the article author provided give me only the
impression "OK it's weirder syntax but it's not so far from what would have to
be written in C anyway, so where's the advantage?"

What I consider missing for "properly" interfacing with C is for Rust to be
able to slurp C headers as they are, without the need for additional
"translation" files that are presented in the article. At least the headers
without the definitions of the functions. But the declarations of the
structures and functions and even basic preprocessing were really, really
convenient.

~~~
acqq
I've took a look on one "real" example, I admit I haven't spent much time with
the language, I just want to get the idea looking at the code which really
does something, I like that more than starting with boring tutorials:

[https://github.com/mozilla/rust/blob/master/src/libextra/jso...](https://github.com/mozilla/rust/blob/master/src/libextra/json.rs)

I know it's the least interesting thing, but for me the simplest rule to
recognize Rust vs Go is that at the moment Go has the nice and minimalistic :=
and Rust the clumsy (for my aesthetics at least) "let."

Still, I understand that Rust attempts to solve more than Go in some aspects,
and I really hope it can succeed. For that, yay Rust!

Can somebody explain me the reason for constructs like this:

    
    
        self.error(~"trailing characters")
    

vs

    
    
         self.parse_ident("ull", Null),
    

I read that ~ means "owned box on heap." Why should something that are facto
string literals be owned and on heap? Isn't the need to allocate and box
string literals on the heap something that makes the language unnecessarily
slow? And why there's a need somewhere to explicitly box something that's
known at the compile time and somewhere there isn't?

~~~
pcwalton
> I know it's the least interesting thing, but for me the simplest rule to
> recognize Rust vs Go is that at the moment Go has the nice and minimalistic
> := and Rust the clumsy (for my aesthetics at least) "let."

It is not possible for us to have ":=" because we don't know whether to parse
a pattern or an expression without a prefix token like "let". Rust's pattern
language is far more expressive than Go's and one grammar will not cover both.

> Why should something that are facto string literals be owned and on heap?
> Isn't the need to allocate and box string literals on the heap something
> that makes the language unnecessarily slow?

Probably the `error` method explicitly asked for a heap-allocated string,
perhaps because it wants to pass it to someone who will later free it. (Unlike
in C, it would be a type error to attempt to free a constant string in read-
only memory, which is what a plain string literal is in Rust.)

~~~
acqq
Does it mean that to do

    
    
        self.error(~"trailing characters")
    

there has to be the complete allocation of enough memory to store the copy of
the whole string, then copying of all characters there, only in order for the
target function to be able to do "free"? If the intention of the language is
to "properly" work with a lot of strings (and it should be) it would be good
not to have glaring inefficiencies? Wouldn't it be a good optimization to have
the free routine check if the pointer is inside of the static area and then
not do anything. That way you can pass the pointer to the static area avoiding
copying and also avoid freeing. And the only thing needed is that free has
"static_begin" and "static_end" addresses?

There are also other possibilities -- by knowing that the heap allocated
things have lower bits of addresses 0 you can mark the stuff using the lowest
bits of pointers.

I know, I have maybe too low level approach. But why not, as soon as you want
to be more convenient than C, you have to think low level too.

Still what I like is that at least at the moment this explicit declaration of
boxing gives a nice feeling that nothing is done "behind the back" of the
programmer, which is good -- the main problem of C++ is that you can't know if
somebody hid something very nasty behind some plain innocent looking
construct, or even what the compiler will implicitly do or won't.

EDIT-addition: Regarding "pattern" if the := would be a single token, not
allowed in patterns, wouldn't it be OK then? Do you have such a valid sequence
in the patterns as the combination of the single operators or whatever?

~~~
pcwalton
> If the intention of the language is to "properly" work with a lot of strings
> (and it should be) it would be good not to have glaring inefficiencies?
> Wouldn't it be a good optimization to have the free routine check if the
> pointer is inside of the static area and then not do anything.

You can implement that yourself, by using an enum for example or by using a
custom smart pointer. The moment you start adding more magic to "free" beyond
"call free" you become less low level of a language.

~~~
acqq
Can I ask in the language if the address points to the item constructed by the
compiler in the static area?

The thing I miss most in C is the possibility for the some kind
of"introspection" \-- reaching out to the info that the compiler or linker has
to know anyway. As far as I know D language is very good for such things.

~~~
dbaupp
You can use lifetimes to enforce that a certain thing is static data, and
combined with an enum, you get the best of both worlds: compile-time constants
require no allocations, but still flexible enough to allow run-time
construction:

    
    
      enum StringRef {
          Static(&'static str),
          Owned(~str)
      }
    

and then `error` would take `StringRef` and be called like:

    
    
      self.error(Static("trailing characters"))
      // or
      self.error(Owned(fmt!("%u trailing characters", count)))
    

(There was even a pull request that added this and the corresponding one for
vectors to the stdlib, but it didn't landed (yet):
[https://github.com/mozilla/rust/pull/7599](https://github.com/mozilla/rust/pull/7599))

------
buster
I must say i am really surprised about the presented features of the language.
It seems to take a lot of the nice things of more dynamic languages and puts
them into a fast, compiled system language. I will have to try Rust, now!

------
regis
Rust looks really great and I would love to switch all of my C development
over to Rust but last time I tried to compile it, it took a good hour or two.
Has this changed at all?

~~~
pcwalton
Well, we have a production-quality optimizer (LLVM). So it'll always take some
time to compile.

Eventually once all of our LLVM patches are upstream and the versions
including the patches make it into common repositories you may be able to use
your system LLVM to compile the Rust compiler, at which point the compile
times will drop dramatically.

We continue to work on compile speed of Rust code all the time.

~~~
copx
Will you also work on providing a better Windows package? I don't understand
why you don't just bundle all the dependencies, given that they all seem to be
open source and redistributable.

Call me spoiled but I expect a one-click installer in this day and age. I
still haven't tried to actually use Rust because of that and I am sure I am
not the only one.

~~~
dbaupp
You're spoiled :P

But, windows is (unfortunately) a bit of a second class platform at the moment
(although there have been some very big strides in the last week or so). So
part of the reason for poor windows packaging is Rust isn't ready on windows
yet (even more so that its normal pre-alpha-ness on Linux and Mac).

------
general_failure
Why do people keep reinventing syntax? Quick tell me what the following mean:

struct Digest { digest: ~[u8] } // what's ~ here?

for self.digest.iter().advance |&byte| { acc = acc.append(fmt!("%02x", byte as
uint)); } acc

What does the above mean? acc as a separate line and nothing else

I hate it when people reinvent the same construct that can be found in other
languages but differently. I guess they want to do something different in
their language, is it?

~~~
mcpherrinm
Rust does have some new syntax, but I think most of it is justified for making
programming in it nicer.

The `~[u8]` would be written `std::unique_ptr<u8>` in C++. They're used
everywhere in Rust, and having to write out unique_ptr would get awfully
tiresome.

The `acc` on its own line is a result of "the last statement gets returned"
like many functional languages do. If you were writing C++, you'd write
`return acc;` instead. This one is more of a convenience, and you could get
away without it.

~~~
masklinn
> The `~[u8]` would be written `std::unique_ptr<u8>` in C++.

Wouldn't it be `std::unique_ptr<std::vector<u8>>`?

~~~
mcpherrinm
Indeed, it would.

