
A 30 minute introduction to Rust - steveklabnik
http://words.steveklabnik.com/a-30-minute-introduction-to-rust
======
ChuckMcM
This is an excellent summary Steve, it also points out one of the challenges
of 'System' languages, which is the requirement for 'unsafe.'

One of the first things I did when I started working on Oak (which became
Java) was to see about writing an OS in it. The idea being that if you could
write an OS in a 'safe' language then you could have a more reliable OS. But
we were unable to write it completely in Oak/Java and that lead to some
interesting discussions about what might be the minimum set of 'unsafe'
actions might be required by a systems language.

Sadly we did not get to explore that very much, although I did pass it on as a
possible thesis topic to some interns who came through Sun at the time. I'd be
interested in your experience with what actions require 'unsafe' and if you
have seen a canonical set that might point toward a process to get to a 'safe'
OS.

~~~
kibwen
For reference, the following actions are what are enabled within `unsafe`
blocks in Rust:

1\. Dereferencing raw pointers (a.k.a. "unsafe" pointers). Note that's _just_
dereferencing: there's nothing inherently unsafe about just creating and
passing around the pointers themselves.

2\. Calling a Rust function that has been marked with the entirely-optional
`unsafe` keyword.

3\. Calling an external function via the C FFI, all of which are automatically
considered unsafe.

~~~
valtron
Don't points 2 & 3 together imply that anything that uses built-ins, which I
assume are implemented with C FFI, is `unsafe`?

~~~
evincarofautumn
No, “unsafe” means “evaluate this unsafe block as though it were safe”. This
enables Modula-style safe interfaces for unsafe implementations.

------
minimax
I think we can be a little bit more charitable towards C++. Modern compilers
will let you know if you try to do something as obviously incorrect as
returning a pointer to a stack variable.

    
    
        $ cat > foo.cpp <<EOF
        > int *dangling(void)
        > {
        >     int i = 1234;
        >     return &i;
        > }
        > EOF
        
        $ clang++ -Werror -c foo.cpp
        foo.cpp:4:13: error: address of stack memory associated with local variable 'i'
              returned [-Werror,-Wreturn-stack-address]
            return &i;
                    ^
        1 error generated.

~~~
steveklabnik
Thank you! Maybe I should explicitly show a new/free example instead, or does
that end up having a similar warning?

I haven't written serious C++ in years, so I have some blind spots. Others on
the Rust team have done quite a bit, so they tend to pick up my slack in
exactly this manner.

~~~
minimax
I wasn't trying to undermine your argument. Rust is solving real problems. Use
after free and double free are still issues in the C world. In modern C++ we
are (hopefully) using smart pointers (std::unique_ptr, std::shared_ptr) to
manage heap-allocated object lifetimes.

~~~
pcwalton
> In modern C++ we are (hopefully) using smart pointers (std::unique_ptr,
> std::shared_ptr) to manage heap-allocated object lifetimes.

Those aren't safe. There are many ways to cause use-after-free with
unique_ptr: for example, placing a uniquely-owned object in a vector and
clearing the vector in a method call on that object.

~~~
pjmlp
True, and hopefully the likes of D, Rust and Go will improve the situation.

In the mean time, we can take advantage of modern C++ safe constructs instead
of keep on using C, as new language adoption always takes time.

~~~
masklinn
Go being mandatorily GC'd I don't think it's relevant to the issue of
improving on C/C++ for their existing use cases.

~~~
pjmlp
There are still lots of user space applications written in C/C++ nowadays,
that could be easily rewriten in Go or any other safer language with native
code compilers, without noticeble performance lost for the problem being
solved.

~~~
masklinn
Sure but if a GC'd language is acceptable for the application, the problem
"was solved" years ago, the tooling not being the issue anymore.

~~~
stusmall
Sometimes these applications are written in C for the extreme portability
rather than performance. I have a couple open source projects in mind that
support a huge selection of OSes and hardware configurations that would not be
possible with some of the other current higher level language but almost every
platform supports C to some degree. I don't know how well Go supports weird
configurations like MMU-less uClinux installs but the GC wouldn't be what is
breaking it.

~~~
Jhsto
I don't really understand concepts of low level languages, but I've had a
perception that if I'd wrote a program in Go using the standard libary and
compiled it with go build it would run on all imaginable platforms. Now, as
far as I've understood your comment suggests that I'm wrong.

Lets suppose that some corporation would download the binaries of my project
and use it on an embedded system, would it run?

~~~
stusmall
It depends on how "embedded" embedded means to you. I've talked to some people
who call a CPE Linux/Atom box embedded and I know some people who don't
consider anything with an OS embedded. I won't even touch that argument. :)

But I used MMU-less uClinux as an example because it breaks a lot of
assumptions that are made in a lot of code. No dynamic linking(which if I
remember go doesn't support by default, or does it even support at all? I
haven't written any in a year or two), no protected memory, and no real fork
(vfork instead) crosses a lot of code off the list on what you can run. I
don't know if go _can_ support it, but I know that the current offical
toolchains don't. There may be a feature go has that prevents them running on
a platform like this, but it won't be GC. There are some GC'd languages that
will run on this platform.

C is great in that is makes very few assumptions and if written carefully can
be _extremely_ portable. The base language doesn't even assume there is an OS
present. I've only run into one platform that had very little C support. It
was a small 8 bit uC that had a very strange execution stack that made C as
everyone uses it hard to efficiently implement.

------
tptacek
This isn't so much an introduction to Rust as it is an introduction to Rust's
concurrency model.

The example of returning a reference to an automatic variable isn't super
compelling, since every competent C/C++ programmer knows not to do it. That
bug does pop up every once in awhile, but almost always in the context of a
function that returns a reference to one of many different possible variables
depending on some condition in the function.

Does Rust really call its threads "green threads"? Green threads have a weird
reputation.

Copy like "this allows you to, well, read and write the data" could be
tightened up; it's an attempt at conversational style that doesn't add much.
"That doesn't seem too hard, right?" is another example of the same thing.

How much of Rust concurrency is this covering? How much of its memory model?
Does the whole concept of Rust concurrency and memory protection boil down to
"the language provides an 'unsafe', and then people write libraries to do
things with it"?

~~~
steveklabnik
Salespeople qualify leads by determining if you're ready to buy or not. If
you're not, they stop wasting time on you. The general idea for a quick
introduction is to qualify your lead. So this isn't a "introduction to Rust's
syntax" it's "an introduction to why you should (or should not) care about
Rust."

> since every competent C/C++ programmer knows not to do it.

Everyone knows, yet programs still segfault. The point is that the language
helps you be competent. Static analysis is very useful.

> Does Rust really call its threads "green threads"? Green threads have a
> weird reputation.

I agree. Rust has N:M mapped threads by default, but recently added 1:1 as
well.

> it's an attempt at conversational style that doesn't add much.

I happen to write like I talk, it gets good and bad reviews. A more neutral
style would be more appropriate if/when this gets pulled into Rust itself,
thanks, that's a great point.

> Does the whole concept of Rust concurrency and memory protection boil down
> to "the language provides an 'unsafe', and then people write libraries to do
> things with it"?

I think this is an unfair characterization, but I gave it to you, so that's a
criticism of me, not you. I tried to point out that unsafe exists for
exceptional cases only: it's not something that you need unless you're doing
something dangerous for a specific reason. I personally have only ever written
unsafe when wrapping something with FFI.

Introductions are hard because you never know how much depth to go into; maybe
I should go into these bits a little more in depth.

Thanks for the great feedback. :)

~~~
tptacek
Oh, don't get me wrong, I'm sold on memory protection as a type system
feature. I'm just suggesting that the example you're using might make it sound
less valuable, because returning stack variable references isn't the most
common kind of error made by C programmers; when you do that, more often than
not your program doesn't work at all.

~~~
steveklabnik
Absolutely, I don't want people to think I'm attacking a straw man. Maybe a
heap allocated example would be better?

~~~
masklinn
Probably, with a slightly tricky ownership issue leading to use after free (a
well known source of exploits
[http://cwe.mitre.org/data/definitions/416.html](http://cwe.mitre.org/data/definitions/416.html))
e.g. allocate to the heap, pass to a function which deallocates it (assuming
that it has ownership) and use it after the call, e.g.

    
    
        #include <stdlib.h>
        #include <stdio.h>
    
    
        void destroyer(int* val) {
          printf("%d\n", *val);
          free(val);
        }
    
        int main(int argc, char** argv) {
          int* v = malloc(sizeof(int));
          *v = 3;
          destroyer(v);
          printf("%d\n", *v);
          return 0
        }
    

Which compiles without warnings using Clang (unless -Weverything, and even
then the warnings are not related to use-after-free), works "correctly" in O0
and O1 (prints "3" twice) then breaks starting at O2 (prints "3" then "0").
(note: it always prints "3" twice with GCC 4.8, showing how fun these things
are)

meanwhile the equivalent

    
    
        fn main() {
            let v = ~3;
            destroyer(v);
            println!("{}", *v)
        }
    
        fn destroyer(val: ~int) {
            println!("{}", *val)
        }
    

refuses to compile and explains why:

    
    
        test.rs:4:20: 4:21 error: use of moved value: `v`
        test.rs:4     println!("{}", *v)
                                      ^
        note: in expansion of format_args!
        <std-macros>:224:8: 224:50 note: expansion site
        <std-macros>:223:4: 225:6 note: in expansion of format!
        <std-macros>:241:45: 241:63 note: expansion site
        <std-macros>:240:4: 242:5 note: in expansion of println!
        test.rs:4:4: 5:1 note: expansion site
        test.rs:3:14: 3:15 note: `v` moved here because it has type `~int`, which is non-copyable (perhaps you meant to use clone()?)
        test.rs:3     destroyer(v);
                                ^
        error: aborting due to previous error
    

which can be fixed either by explicitly cloning the value, or by altering the
sub-function to not consider it owns the pointer (or by removing the
`println!` call in `main()`, thus transferring the ownership of the pointer to
the sub-function safely, of course)

~~~
pbsd
Analogous example in C++11, using unique_ptr (which Rust's owned pointer
models):

    
    
        #include <stdio.h>
        #include <memory>
    
        void destroyer(std::unique_ptr<int> x)
        {
            printf("%d\n", *x);
            // x is deallocated here
        }
    
        int main()
        {
            auto x = std::make_unique<int>(3);
            // destroyer(x); ERROR: ownership must be transferred explicitly
            destroyer(move(x)); // Override with an explicit move
            printf("%d\n", *x); // Guaranteed to segfault
            return 0;
        }
    

This is somewhat more helpful, but sadly the compiler cannot monitor the state
of x at compile time, like Rust. The upside is that this bug is easy to catch
since the invalid access is guaranteed to try to access a null pointer, and
will crash instead of giving garbled results.

~~~
pcwalton
> The upside is that this bug is easy to catch since the invalid access is
> guaranteed to try to access a null pointer, and will crash instead of giving
> garbled results.

GCC and LLVM optimize based on the assumption that null pointers are never
dereferenced, so this is actually undefined behavior, no? Anything can happen.

~~~
pbsd
You're right that it's UB, good point. It's hard to think what a sane compiler
would do in this case besides going through with the dereference, though.

~~~
dbaupp
A pointer dereference allows the compiler to assume that a pointer is non-
NULL, so it can then perform "invalid" optimisations (like dead-code removal),
this post contains an very small example: [http://blog.llvm.org/2011/05/what-
every-c-programmer-should-...](http://blog.llvm.org/2011/05/what-every-c-
programmer-should-know_14.html)

------
pcwalton
I like this tutorial because dives straight into the most unique/unfamiliar
parts of Rust (ownership/references) and gets them out of the way. It's a
"learn the hard way"-style tutorial, and I think that's the best approach.
Once you learn how ownership and borrowing work, along with ARCs and
concurrency, everything else is really simple and just naturally falls out.

~~~
haberman
Agreed. I'd love to see an even more in depth document that takes a wide range
of ownership/allocation patterns that are common in C and C++, shows Rust
equivalents, and analyses why Rust can or cannot prove that they are safe
(i.e. whether they require unsafe blocks or not). I don't have an intuitive
sense yet for the boundaries of what Rust can automatically prove safe. How
much C and C++ could be directly translated into safe Rust and how much would
need to be reworked or put in unsafe blocks?

------
brson
I like this a lot, and think it's the best intro to Rust yet. The thing that
concerns me a bit is that it presents the special cases in concurrency without
impressing some of the most important points. Primarily, the channel example
presents the send as _copying_ , which in this case it is, but one of the main
advantages of Rust's channels and owned types is that message passing of heap-
allocated types do not need to copy. It probably doesn't stress hard enough
that Rust tasks do not share memory before saying, 'oh, but really you can
share memory if you need to', though I see that the Arc and RWArc examples are
good ways to introduce the concept of using unsafe code to provide safe
abstractions.

------
noelwelsh
The focus on C++ as point of comparison is understandable given Mozilla's
background, but in Internet land most systems software runs on the JVM, and is
written in Java, or increasingly, Scala (see LinkedIn and Twitter, for
example).

The issues of memory layout and the like come up here, and unlike Rust the JVM
doesn't give much control of this aspect. See Martin Thompson's blog for an
example of someone very concerned with issues of performance on the JVM
([http://mechanical-sympathy.blogspot.co.uk/](http://mechanical-
sympathy.blogspot.co.uk/)) I believe Rust could see a lot of adoption within
this community as a "better" Scala -- a modern high-level language that allows
dropping down to bit-twiddling when performance is an issue. It needs higher
kinded types before it will work for me, but I hear that is on the road-map.

BTW, I've read a few Rust tutorials and they all fail for me in the same way:
too much waffle and not enough getting down to the details. I understand the
difference between stack allocation, reference counting, and GC, I get why
shared mutable state is a bad idea, etc. What I want is a short document
laying out the knobs Rust provides (mutable vs immutable, ownership,
allocation) and how I can twiddle said knobs.

~~~
Aloisius
_but in Internet land most systems software runs on the JVM, and is written in
Java_

[[Citation needed]].

The Internet land I've lived in mostly lives in C with a smattering of non-JVM
scripting languages (Python, Ruby, PHP, etc) on top.

~~~
mbreese
It's probably more accurate to say that in the Enterprise most software is
running on the JVM. But there are certain (large) internet companies that have
significant system software running on the JVM (Google, Twitter).

------
samth
I think the emphasis on "unsafe" isn't helpful. As far as I can tell, the only
thing that "unsafe" is enabling is that Arc and RWArc are written in Rust
rather than in C in the runtime (the way they'd be in Go, or Erlang, or
Haskell). The things that make Rust able to do what it does are ownership and
tasks and lifetimes and affine types -- all the things the post covers before
talking about "unsafe".

Also, it gives the impression that there's something fundamentally unsafe
about all of this, whereas the whole point is that these abstractions are
_safe_ to use.

~~~
steveklabnik
> Also, it gives the impression that there's something fundamentally unsafe
> about all of this, whereas the whole point is that these abstractions are
> _safe_ to use.

Right, this is my point. I should find a way to make it a bit more clear.

I wrote it this way because the systems people I talk to are skeptical at
times that a compiler knows best. After all, there's a reason you want that
low-level control in the first place, right? The ability to escape things when
you have to relaxes people.

~~~
samth
> I wrote it this way because the systems people I talk to are skeptical at
> times that a compiler knows best.

Well, the best way to combat that would be demonstrate that cool things can be
done safely in Rust, but that probably requires a lot more than fits in your
introduction.

I think you could allay that fear by addressing it directly, rather than
saying that Rust's secret sauce is unsafety.

~~~
steveklabnik
Hm. I thought that talking about building ARC and discussing its
implementation was something cool that directly addresses it. What would you
like to see?

~~~
samth
I think talking about how ARC is implemented in Rust is cool. I would just
pitch it differently.

I think what I don't like about your current description is that it makes it
seem like unsafety is what allows you to _have_ Arc in the language. Instead,
unsafe blocks are what allow you to _implement_ Arc inside the language.

I'd start the footnote this way:

\---------------

A footnote: Implementing Arc

So, the Rust language doesn't let us use shared mutable state in dangerous
ways, but what happens if we really need to get down and dirty? For example,
what if we wanted to _implement_ `Arc` ourselves?

In fact, `Arc` and `RWArc` are both implemented in Rust. Inside their
implementations, they use locks, low-level memory operations, and everything
else you might see in a C++ program. However, anytime we use these features,
we have to wrap them in an `unsafe` block.

...

\---------------

I hope that conveys the different emphasis that I'm talking about.

~~~
steveklabnik
Certainly. Thanks. That's much more clear.

------
danso
A little OT...but what's with Svbtle's apparent default styling of links?
There's no indication that any particular word or sentence contains a link,
which basically makes those links invisible to readers. Or do lots of people
read web articles by randomly hovering the mouse around the text?

But relevant to the OP...I generally try to save useful tutorials like this on
my pinboard, which often doesn't pick up the meta-description text. So I
double-click to copy the first paragraph and paste it into pinboard...except
in the OP, I kept on clicking on text that was hiding links underneath.

It's a strange UI decision, and one that seems to discourage the use of
outbound links...if you can't see the links, then what is the purpose of them?
For spiders?

~~~
Zecc
> There's no indication that any particular word or sentence contains a link

There is a subtle grey underline, which I'm sure can be nearly invisible
depending on your screen.

~~~
kibwen
Allow me to save everyone from opening their devtools:

    
    
      background-color: #FFF;
      border-bottom: 2px solid #F4F4F4;
    

In RGB, that's the difference between 255 and 244. It's more than a little
absurd.

------
acqq
"Rust does not have the concept of null."

How can I have the pointer to something that is maybe allocated or maybe
present? Do I have to have additional booleans for such uses? Isn't that a
waste?

How can I effectively build complex data structures like graphs, tries etc
then?

I'd like to see that covered too.

~~~
kibwen
Rust uses the `Option` type for that (name taken from Scala and ML, it's
called `Maybe` in Haskell).

[http://static.rust-
lang.org/doc/master/std/option/index.html](http://static.rust-
lang.org/doc/master/std/option/index.html)

What's neat is that if you stuff a pointer inside an `Option`, then not only
is it guaranteed to be memory-safe but it also compiles down to a plain old
nullable pointer at runtime, so there's no extra overhead while still
retaining safety.

~~~
acqq
So it doesn't have "null" but it has "None." On the linked page:

    
    
         // Remove the contained string, destroying the Option
         let unwrapped_msg = match msg {
             Some(m) => m,
             None => ~"default message"
         };
    

Now why is there that ";" at the end? Before that there is a construct without
it:

    
    
        // Take a reference to the contained string
        match msg {
            Some(ref m) => println!("{}", *m),
            None => ()
        }
    

And did we have take the "reference" to print the value of m?

And one note more: the linked page doesn't explain that the Some actually
introduces "Option" type. It writes about the Option but the code uses just
"Some."

    
    
         let msg = Some(~"howdy");
    

Some as a "keyword" seems to have two different semantical purposes, depending
if it's in the "match" or not. I don't see that explained too.

~~~
steveklabnik
Most of this is out of the scope of this tutorial, but is in the comprehensive
one.

match is an expression, but let is a statement. In the first example, the
match expression is used inside of the let statement, in order to produce what
is assigned.

I'm not 100% sure if you _must_ take that reference, but given that it's a
pointer, that makes sense. In the previous version, it's simply returning a
value, but println! needs the contents, not the pointer itself.

Inside the linked Option enum, it shows both: [http://static.rust-
lang.org/doc/master/std/option/enum.Optio...](http://static.rust-
lang.org/doc/master/std/option/enum.Option.html)

It's an enum like any other.

That said, these are all good points, and this documentation should be
improved. Thanks, I'll add this to my list.

------
maxerickson
I personally dislike the style of tutorial that has lots of 'we' and 'lets' in
it.

I suppose part of that comes from the tendency for such tutorials to provide
revelations instead of motivators. For example, in this tutorial there is
'look at this C++ code because I said to' and then two sentences later it
explains that the C++ code ends up in a garbage value.

But this is probably very much a point of style and I'm sure lots of people
think my view is stupid.

~~~
steveklabnik
I tend to be very collectively focused, so I do tend to write this way. Thanks
for the feedback; the style may not be appropriate for an official tutorial.

> the tendency for such tutorials to provide revelations instead of
> motivators.

I'm going to have to think about this, that's very interesting. I would like
to say that my revelations provide motivation, but that may be wishful
thinking...

Do you think there's a way to demonstrate these concepts in a way without 'the
reveal'? It seems to me that comparison will always feel a bit reveal-y, as
demonstrating some kind of difference is inherent in comparison.

~~~
maxerickson
Well, try to state the motivation prior to the explanation.

"The second function in this C++ code does not properly initialize num":

...

"How does that happen?"

...

"Rust avoids this by"

...

~~~
steveklabnik
Great, thank you.

------
patrickaljord
Thanks for the the tutorial! Rust seems a bit too complex to me. Like a C++ on
steroid that wants to do and be everything. Nothing wrong with that but not my
cup of tea. I'd rather stick to C if I need tight memory management, it is way
simpler and straight forward. And if I need concurrency, I'll stick to Golang
(or erlang). Really, it's such a pleasure to read some golang after reading
this 30 minutes of Rust. Anyway, just my opinion.

~~~
pcwalton
> Rust seems a bit too complex to me. Like a C++ on steroid that wants to do
> and be everything.

No, that's explicitly not a goal. The goal is to enable zero-cost abstractions
and memory safety. Everything here is in service of that goal.

> I'd rather stick to C if I need tight memory management, it is way simpler
> and straight forward.

The problem is that the "simple and straightforward" model of C leads to a lot
of very not-simple-and-straightforward time in front of Valgrind to get the
program to work, or worse, to fix security vulnerabilities.

------
rcthompson
Thanks for this straightforward and accessible intro to some of Rust's unique
features!

~~~
steveklabnik
You're very welcome.

------
steveklabnik
I like the overall structure, but I'm not sure about throwing so much syntax
without explaining it in detail.

~~~
ncallaway
I actually liked the amount of detail in explaining the syntax. For the most
part, the code samples are very readable and understandable as they are (and I
haven't written any Rust).

I think explaining a lot of the syntax would have made this more of a "how to
Rust" article, rather than a "why to Rust" article. I really appreciated the
"why to Rust" tone of this article, and it provides a great explanation of why
the language is different from C / C++ and why I should care.

~~~
steveklabnik
Excellent. Thank you.

It's hard to have a beginner's mindset after you've done something for a year.

------
niix
Thanks for this. I've been thinking about getting into Rust recently and this
motivates me to do so now.

~~~
steveklabnik
Excellent. You're very welcome. :)

------
Jemaclus
The last time I touched C code was my sophomore year in college, so maybe 12
years ago? As a result, the last time I had to deal with pointers and such was
back then, as well.

I'm primarily a web-dev. Ruby, PHP, and Javascript are the languages I'm most
familiar with at the moment.

Are there any Rust for Dummies-style tutorials floating around? As simple as
this introduction is, it was still over my head...

~~~
steveklabnik
I have you covered in that case as well:
[http://www.rustforrubyists.com/](http://www.rustforrubyists.com/)

I want to provide a version of the 30 minute intro that's not strictly for
systems people as well, but you have to start somewhere.

~~~
rubiquity
Do you see Rust as a language that people will write the business domain type
applications in or as a supplement to languages like Ruby, Python, etc. to
write those "gotta have performance here" parts of the application?

~~~
steveklabnik
The second ever (that we know of) use of Rust in production is by Tilde, who
are using Rust embedded in Ruby for Skylight to help ensure that memory usage
stays down and to get more consistent performance. Garbage collection while
doing performance monitoring is bad news.

I'm not entirely sure yet. I wrote another post that touches on this:
[http://words.steveklabnik.com/rust-is-surprisingly-
expressiv...](http://words.steveklabnik.com/rust-is-surprisingly-expressive)

I think that it's possible that Rust might eventually be useful as an
application level language. We'll see how it shakes out. We've been in love
with scripting languages for the past few years, but now their drawbacks are
becoming more apparent. Look at all the Rubyists and Pythonistas flocking to
Go, for example...

Interesting times indeed.

------
bsaul
Is rust borrowing any kind of code from what is used for objective C ARC
technology relative to detecting the lifetime of a variable and automaticaly
freeing the resource ? Is it a common known algorithm ?

~~~
steveklabnik
Everything is written in Rust, so we're not borrowing the code.

Reference counting is very common:
[http://en.wikipedia.org/wiki/Reference_counting](http://en.wikipedia.org/wiki/Reference_counting)

~~~
bsaul
I had the impression that rust and ARC were doing a bit of static code
analysis to detect when a "reference count decrease/increase" could be
performed ( thus the "automatic" part in ARC), and insert code at compile
time. Which seems a bit more complicated than simply decrease them dynamically
when a pointing is object is destroyed. But now that i come to think of it,
things look a little blurry for me on that part.

------
0x001E84EE
I'm a big fan of that kudos button! Very nice website and an interesting
introduction to Rust.

~~~
nfoz
I find it annoying to the point of offensive. Actions being actived on mouse-
hover is terrible; I did _not_ intend to give "kudos" but was curious what
might be linked under it, and suddenly an action is recorded. Now I can't
consider any webpage safe and have to watch where my mouse goes; that's wrong.

~~~
BlackDeath3
Three cheers for NoScript!

I understand that it doesn't really solve your problem, but if it's safety
you're worried about...

------
45g
> You can see how this makes it impossible to mutate the state without
> remembering to aquire the lock.

Not quite true. Looking at the type signature of e.g. RWArc::write I see this:

    
    
        fn write<U>(&self, blk: |x: &mut T| -> U) -> U
    

which means I could probably do:

    
    
        let mut n = local_arc.write(|nums| {
             nums[num] += 1;
             return ~(*nums);
         });
        n[2] = 42;

~~~
eridius
You're not letting anything escape. You're copying `nums` and then mutating
your copy. And this only works because `nums` can be implicitly copied like
this. If you changed it from `[int, ..3]` to `~[int]` you'd get a compiler
error (as `~[T]` cannot be implicitly copied).

