A 30 minute introduction to Rust
words.steveklabnik.com
words.steveklabnik.com
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.
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.
Sure there is. Passing around multiple pointers can result in a double free and then the dangerous dereference can happen. I'm guessing the developer must be careful when writing unsafe blocks to make sure this doesn't happen.
- dereferencing
- arithmetic (implemented as ptr.offset(number) in the stdlib),
since it is undefined behaviour for LLVM to move a pointer to
point outside* of the object that it came from originally
(even without deferencing)
Everything else is OK. (Although the only other thing possible is passing it around as "black box" value.)*One byte past the end is ok.
Some of my closest friends in college specialized in operating systems, and we (mostly them) worked on http://xomb.org , an exokernel in D. I'd hope that today we'd choose Rust instead.
Julia Evans has been writing _fantastic_ series about a kernel in Rust: http://jvns.ca/blog/categories/kernel/
As she says "This is typical of a lot of Rust code I’m writing – I need to write a lot of unsafe code."
I'll have to give this 'minimum set' idea some thought. I think that safety will be more useful for things like kernel modules than in the kernel itself, though I'm not sure why I think that, exactly. Hmmmmm...
> I need to write a lot of unsafe code.
To contrast with application-level code, pcwalton has measured that less than 1% of Servo's code is contained within `unsafe` blocks.Much of the kernel is implemented in managed code.
IBM did Jikes RVM (old name: Jalapeno) which was mostly, if not purely Java. They handled the bootstrapping problem with some clever ahead-of-time compilation + meta-programming. Even their GC is implemented in Java.
googles
Jikes RVM is an absolutely amazing project. Superb work. And i'm very glad to see it's still under somewhat active development!
$ 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.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.
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.
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.
Lets suppose that some corporation would download the binaries of my project and use it on an embedded system, would it run?
Don't mix languages with implementations.
Currently there are two native compiler toolchains for Go, which only support a given set of OSs and computer architectures.
Additionally some people written Go interpreters with another set of supported targets.
So to answer your question, it would run on the embedded system if :
1 - the hardware could cope with Go runtime requirements
2 - it would be a supported target for one available native code toolchain
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.
Go compiles to native code, not bytecode. Your post makes it seem like you might be missing this fact.
Go has good cross-compile support so from say a Windows box I can compile a Go program using just the standard library that will run on Windows, or I can compile one that runs on MacOS, or I can compile one that runs on Linux, and I can even compile one that runs on a different processor arch (like I can be running Windows/x86 and compile a binary for Linux/ARM, for example).
But(!) you have to compile a separate binary for each of those platforms, you can't compile just one single executable that runs on all of those systems. The output of the Go compiler is native machine language code for a specific architecture and OS.
eg. I want to compile an http server and run it on either a Windows/x64 box or a chumby Linux device and I'm currently on a Linux/x86 system:
cd mygoprogram
export GOARCH=arm
export GOARM=5
export GOOS=linux
go build
I now have an executable in the current working directory named "mygoprogram" that will run on a Linux system with an ARMv5 processor (say, an old chumby device)
export GOARCH=amd64
export GOOS=windows
go build
I now have an executable in the current working directory named mygoprogram.exe that will run on a Windows/x64 system, but it is completely separate from the binary that will run on the Linux/ARM device despite being built from the same source code.
mygoprogram.exe will not run on the Linux system, and vice versa. Go is like C/C++ in this regard as opposed to say Java where a common bytecode format will make the compiled code still platform independent.
Shipping a VM with the product is not always possible/desireable.
And these are off the top of my head, I'm sure there are others.
I am also active on D forums.
However the mainstream developers aren't aware, or even care, about those languages. Which leaves us in the current state of affairs in the industry.
(Yes you can work around the current GC's but this drives away some developers)
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"?
> 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. :)
#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)Another option is to say something like, "For the sake of brevity, this is a very simple and arguably obvious violation of safety. In practice, there are many subtle and hard-to-diagnose sources of unsafety in C++, even when you use safer abstractions like shared_ptr." This allows you to avoid getting sidetracked and losing your reader, while heading off skepticism of readers with more knowledge about C++.
#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.GCC and LLVM optimize based on the assumption that null pointers are never dereferenced, so this is actually undefined behavior, no? Anything can happen.
main.c:14:20: warning: Use of memory after it is freed
printf("%d\n", *v);
^~http://bluishcoder.co.nz/2012/08/30/safer-handling-of-c-memo...
I think something similar for Rust would make for a great article subject too.
There's nothing wrong with writing casually for a web page that is meant to be inviting to newcomers.
I've ignored Rust links on HN until the subject of your link got me to take a look. The style was fine and you did a good job in at least showing a few snippets of code while advocating the benefits of the language.
Contrary to tptacek's criticisms, I wasn't looking for a dry or comprehensive manual - just something to read in a couple of minutes that would give me an indicator of whether or not I should look further into the language.
Thanks for the article.
Is discussion of unsafe in an introduction article esoterica?
By the way, loved the proposal video [1] you did on docs for rust: it's a pretty solid proposal for any language.
Thanks. :)
I found it unusually clear, which I liked a lot. There was a bit at the end to do with unsafe that was a bit difficult to follow, but a sentence like 'but wait, RWArc is just a library, how come it was able to do the thing that I said the compiler wouldn't let you do?' would have cleared it up just fine.
Hmmm. Isn't that what this says?
> So, the Rust language does not allow for shared mutable state, yet I just showed you some code that has it. How’s this possible? The answer: unsafe.
It's that jump from being introduced to RWArc to considering how it might have been implemented that wasn't obvious to me.
I think the style's alright. I also like the tone of the tutorial on the Rust website, don't know if you were involved with that too.
>Thanks for the great feedback. :)
FWIW, I found the feedback to be a little too condescending for what is a volunter effort to help people understand a new language.
Ownership is really central to Rust. It's central to both memory management and concurrency: to work with Rust you need to understand it.
> 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's just a simple example. The same logic also prevents iterator invalidation and use-after-free, which are things that do occur in the real world and lead to security vulnerabilities.
> Does Rust really call its threads "green threads"? Green threads have a weird reputation.
They're M:N threads, multiplexed among multiple hardware threads, like Go or Erlang.
> 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"?
Sort of, but I think that's an uncharitable way to say it. The trick is that the language allows these unsafely-implemented primitives to be safely used from safe code. As long as the unsafe code is correct, the safe code is guaranteed to be safe. From a trust point of view this is really no different from building the features into the compiler: either you trust the compiler (which, as it's a compiler, is unsafe) or you trust the unsafe portions of the standard library. But it's way easier, and more flexible, to hack on libraries than to hack things into the compiler—as you get to write code, not code to generate code.
Furthermore, the safe part of the language is so powerful that you rarely ever need "unsafe": you can do practically everything you might need to do, including shared memory with locks, in the safe language, without GC. Only if you really need to squeeze out the last amount of performance, or if you need to interface with C libraries, do you need "unsafe".
Maybe I should mention some of the more complicated examples explicitly, then?
Oh, I see. In that case yes, there are also explicit lifetimes, which allow you to squeeze out more expressiveness to cover most of C++'s use cases for pointers/references: http://static.rust-lang.org/doc/master/guide-lifetimes.html
There are no more magic pointer types, though; lifetimes are just annotations on references (&).
> On the other hand, building libraries to abstract unsafe pointers has been somewhat discredited by C++ and shared_ptr.
I think we do a lot better than C++. First of all, we believe our system is safe, unlike shared_ptr (proof is in the works). Second, shared_ptr isn't very fast, due to some design decisions like requiring atomic reference counting (which is an order of magnitude slower) and not being intrusive (requiring 2x the allocations). We also allow shared_ptr to be converted into references, allowing the programmer to eliminate a lot of reference count traffic. Most importantly, though, reference counting is something you only use if you actually need multiple references and you don't have one specific place to free the object in: in other words, you don't use reference counting in Rust much more than you'd use reference counting in C. Typical malloc/free patterns are handled with unique pointers.
Not quite. You can use std::make_shared to allocate the object and the ref count in one allocation. You get improved locality of reference as an added bonus.
That's very exciting!
We have done measurements on this for Firefox code. 100% of the security vulnerabilities for Web Audio were memory safety flaws.
They are hard to come by, in this time and age, of cutting down costs everywhere while offshoring components.
Somehow I have this memory, maybe false, that on those days the developers had better skills than most of the younger developers I met on the last five years.
If I'm asked to make an image gallery for a GUI you can bet 99% of people will go for an existing solution out of a matter of productivity, and the reality is that even if I was interested in making a gallery of my own or acquiring a deep understanding of how to make a proper piece of code that solves that problem, it is extremely unlikely I could come up with something better in the span of time I've been allocated to solve it.
Similarly, there's not reason to deal with memory management errors unless you cannot avoid it at all costs. None.
This sounds like vinyl DJs complaining that kids nowadays have DJ software that does beat detection and automatic loops n' shit. Sure, but the production value of your average mix has gone up tremendously now that you don't have to spend 30% of your time beat matching and instead you can now add samples and synths.
For the record, I can program in Assembly and I can DJ with vinyl, but it's been years since I've had a necessity to recur to either. At least the vinyl has some aesthetic, subjective vintage value.
For some of us so does working with assembly and other low-level quirks and domains. :) The challenges and problems, tools and solutions are very differnt and IMO much more interesting than "getting shit done for real life value". To each their own I guess.
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/) 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.
The official tutorial contains much of that information.
The official tutorial isn't very good on issues of memory management. The first mention of managed references (I assume that means GCed) is in an example in section 11. Nowhere does it actually explain what managed means (and if I missed it, I blame the tutorial for not making it explicit enough!)
The official tutorial is really bad but at least has a large bulk of information. I'd love to re-write it, but I haven't had the time.
(And it was more reference counted than actually garbage collected: now we have Rc<T> and Gc<T> for both strategies.)
[[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.
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.
For the most part I failed to see that I -needed- unsafe code in some situations. Instead I was trying (failing) to annotate my code to ridiculous levels with lifetimes. It was really frustrating.
I don't think the current docs do a great job of putting unsafe in a suitable perspective. It's somewhat downplayed IMO.
Still, I've learned now and it's been pretty pleasant after that.
FWIW I've been doing c++ for maybe 18 years, writing device drivers, game engines, compiler development. I thought rust was made for me but it's been tough, much more so than any other language except maybe SML!
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.
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.
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.
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?
There is a subtle grey underline, which I'm sure can be nearly invisible depending on your screen.
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.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.
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.
// 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.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...
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.
The second example is a statement. Thus, we're not using the result of the `match` statement.
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.
> 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.
"The second function in this C++ code does not properly initialize num":
...
"How does that happen?"
...
"Rust avoids this by"
...
I actually find golang harder to read without parametric types (sans built-in slices and maps).
Well, if you don't want your C to segfault, you have to understand these concepts anyway, they're just implicit to the language. C's memory management may be simple, but it's surely not easy.
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.
If you work alone yes. Good luck on a 50+ developer team size, with high atrition rates.
Rust most definitely isn't "like a C++ on steroid" from a complexity standpoint. It tries (and — I think — mostly succeed) to be a significantly simpler and more coherent language.
It does make things which are implicit in C or C++ (e.g. ownership) explicit. That's a good thing, you need to know your ownership in C or C++, the language just doesn't help you much.
Incidentally, I find reading Go to be much more verbose and even heaver cognitively compared to reading Rust code.
I think it's well written, and it makes me interested in learning more about Rust. The one thing I'd like to have seen addressed is type inference.
Also, you don't credit the original author.
"This excellent presentation" is a link.
> But wait, how is that possible? We can’t both allow and disallow mutable state. What gives?
I had to re-read the above a few times. And still don't get it. Steve, what do you mean with it? Are you talking about how are Arc/RWArc implemented? Or is it something else?
I also wasn't sure about the part you quoted, but I was trying to explain that it's not that Rust _doesn't_ allow shared mutable state, it's that while the language doesn't, you can use unsafe to build safe abstractions, so in practice, it does. Hmmm.
First you showed two examples: Arc (to share immutable data) and RWArc (to share mutable data with enforced mutexes around closures). Then you talked about `unsafe`. Seems easy, one needs a "backdoor" to implement RWArc in Rust (at first I thought it was implemented in C/C++).
But (quoted) sentences between Arc/RWArc part and `unsafe` part don't really connect them, at least to me.
A RWArc is shared mutable state: you can have two references to the Arc in two different tasks. Yet I said that Rust throws a compiler error for shared mutable state.
> (at first I thought it was implemented in C/C++).
There's very little C++ in Rust anymore. :)
> Seems easy, one needs a "backdoor" to implement RWArc in Rust
Yup, this is exactly the point with those two sentences. Maybe I should just straight-up remove them.
Or be explicit that you'll now talk about RWArc implementation.
I found it a bit worrying, as when I read that I had to go back and re-read the code a few times to make sure that there wasn't an unsafe block in the code, or perhaps that the use of RWArc implied unsafe, and would then turn that whole function into an automatically unsafe block.
Nevertheless, very cool. I really liked the tutorial, I'm getting quite excited by Rust.
I think we've now got none, except for LLVM in the compiler, which means any binaries built using the stdlib don't need any C++ libraries (to be clear, libraries without the stdlib have never needed any).
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.
It's hard to have a beginner's mindset after you've done something for a year.
When it comes to showing new languages to experienced programmers, I prefer showing code, and explaining what it accomplishes. Experienced programmers will start building up a Bayesian model of the syntax without being explicitly told.
I think of this as the "Dive Into Python" approach: http://www.diveintopython.net/
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...
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.
I'm not entirely sure yet. I wrote another post that touches on this: http://words.steveklabnik.com/rust-is-surprisingly-expressiv...
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.
- embedded systems
- games
- high performance + high correctness environments
Personally, I don't see it as a web-app or line of business app development languages. But it will allow you to create the components that the webapp and LoB apps call into. But I imagine if some people really like Rust for those purposes, they will start building the libraries and code infrastructure to make it easy and away we go.
Reference counting is very common: http://en.wikipedia.org/wiki/Reference_counting
I understand that it doesn't really solve your problem, but if it's safety you're worried about...
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;