69 comments

[ 3.7 ms ] story [ 146 ms ] thread
By using a garbage collector, Go must compete with python, ruby, haskell, clojure, java, scala, c#, etc. Maybe Go is nice for some things, but it seems like an incremental improvement over the next best alternative.

Rust only needs to compete against c, c++, Ada, etc. In that class of languages, safety is a major feature.

This is so much more important than people are generally aware of. We are leaving the point in time that writing highly bug-prone C or C++ is justifiable due to performance concerns. The justifiability of these up until now is a huge reason why governments and organized crime have been able to buy the keys to our servers and personal machines. We are going to be able to replace ubiquitous, critical, buggy code with something that will significantly increase the costs of finding and exploiting RCE vulnerabilities. This is so huge.
For now, I don't think Rust is as performant as C/C++. Although it should be able to match C/C++ speed, I think there are some cases where the output was slower than expected.
You are absolutely correct. I should say that the THEORETICAL performance of Rust may be competitive with C++, maybe even faster in some cases, but that work remains to be done to get it there. My above statement assumes that this day will come, or that the performance at least reaches a point that will allow a reasonable engineer to choose Rust over C or C++ for something that performance is a crucial consideration for.
There are actually cases where Rust is faster than C already, one of the reasons being the compiler emitting better code thanks to mutable aliasing being forbidden.

http://benchmarksgame.alioth.debian.org/u64q/rust.html

It's not why C is faster, it's more about being able to use hand crafted SSE2 instructions and existing libraries with such optimizations. Nothing competes with C when performance really matters.
Feel free to use the asm! macro in rust when you need to. FFI support is also quite good.
You can use "hand-crafted" SSE2 instructions and libraries with the same in Rust. Servo heavily relies on Skia, for example…
Technically Fortran does compete. For computational applications it is faster than C and hence why it's so popular in supercomputing.
There is also a case for making highly optimized C performance easier to attain, without needing to resort to unsafe code. You can do this by providing more invariants to the compiler via a better type system, which gives it more room to optimize. It may never get to the performance of hand-optimized stuff, but for that there is unsafe code blocks.
(comment deleted)
I think the point is that machines are fast enough that being as fast as C++ doesn't matter anymore.
True for many things. But there are still plenty of things that we still want to do faster or cheaper or that we want to feed more data to, and we also still find plenty of new things to do as computers get more powerful.
I find comparing Rust and Go baffling. Both are relatively new, and both compile to native binaries, but their approach and purpose are completely different.

The Go runtime provides GC, its own scheduler, time abstractions -- basically everything a JVM is required to do (plus the scheduler)[1]. It's an AOT-compiled Java. Because of its high-abstraction runtime, interoperation with native libraries is hard to nearly impossible (depending on the direction). It is to be used to write server-side applications. It's Java without the JVM, for better or worse (native binary, short startup, but no dynamic code swapping, no multiple languages support, no instrumentation, no JIT, and no deep monitoring)

Rust, on the other hand, is a modern C/C++ replacement. It is meant to be used anywhere C or C++ are used. It can be used to write applications, device drivers, operating systems, or fully native libraries (that can be called from Java, Go, Python or Fortran).

Neither approach is better than the other, but the two are so different that they can't even be compared directly. One is Java minus the JVM, and the other is a C/C++ replacement.

[1]: GC (or rather the illusion of infinite memory), abstracting OS time plus some other OS abstractions -- all provided by Go but but not Rust), are the only things required from a JVM. Runtime bytecode interpretation or JIT -- what most people usually associate with JVMs -- are actually not required; some JVMs, particularly those for hard realtime and safety critical code, perform AOT compilation.

They are compared because as humans, we are much better at learning new things when contrasted to other things that we are aware of. A concept that has absolutely no parallels with a previously encountered one is much more difficult to understand. From this perspective, it is actually quite useful to compare these two things.
I always thought it was because both languages were (at least at some point) referred to and advertised as 'systems languages', which naturally invited comparisons. However, 'systems' meant different things for each language.

For Go, 'systems' as in the sense of software running on servers providing services to user applications.

For Rust, 'systems' as in the sense of (http://en.wikipedia.org/wiki/System_programming_language) - software such as OSes, device drivers, etc.

Just for fun, Swift is advertised as a systems language as well. In its defense, it does have facilities for bypassing the preferred way of managing memory (ARC) and working with memory directly.

This has indeed encouraged much comparison: there is simply a large overlap in the communities that may be inclined to use either. There was a discussion between the authors of C++, Rust, D, and Go in which the topic of what a "systems programming language" even is is brought into question. Rob Pike, speaking on Go's behalf, mentioned that while "systems programming" was originally advertised as a goal of Go, it has since been dropped from the list, due to the expectations that others have when they read that compared to the intent of the drivers of the language. Here's a video of that talk, if you're curious: http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Pan...
Funny, according to Alexandrescu's definition it is a "systems programming language", after all. Go's memory allocator, garbage collector and runtime are written in Go itself.
I think that if Python can be considered a "systems" language according to somebody's definition, that definition is pretty flawed.
The point is that what constitutes a "system" is not well defined and/or there are multiple conflicting definitions. I was sad to see rust billing itself as a systems language so prominently, given that it doesn't really mean anything.
It's a simple term that, in Rust's case, encompasses all of "bare metal; zero-cost abstractions; no runtime; all language primitives map to simple hardware instructions". I don't see any better word for it. Do you?
That sounds like most of what people mean when they say a low level language, though I admit that the term comes with its own baggage about the simplicity of the language (which doesn't apply to rust).

I guess I think the sentence you wrote above is just a lot more clear than calling it a systems language and hoping people know what you mean.

The two are most compared in communities with a lot webdevs because the last couple of years is when webdevs have started rebounding from the statically typed == bureaucratic enterprise factory bean meme, and will suddenly entertain static types. Then, newly released languages are attractive for the get-in-on-the-ground-floor factor.
They are compared by pretty much anyone that has found both to be significant or interesting. People often compare it to C++ because of the theoretical performance capabilities being similar. People often compare it to Go because Go is a simple, popular reference that many people understand, and hence can be compared against in a way that is meaningful to a lot of people. There are a lot of similarities, as well as a lot of differences, making for lively conversations filled with tangents on various preferences and experiences. In short, you can have a good conversation when making such comparisons. You can compare it against tomatoes, too, but the shared ground isn't huge, and analogies must be far more complex to derive meaning, and the participants need far deeper mental stacks to make ANY progress that relates to the original intent when the tangents veer far from the domain of programming language implementation or usage.
"I could use Rust, but a glance at the concurrency documentation looks like I’ll be spending a lot of my time doing exactly the kind of thread management reference counting minutiae that Go does for me by providing channels."

Actually, rust does provide very similar concurrency primatives. T̶h̶i̶s̶ ̶i̶s̶ ̶a̶ ̶s̶h̶o̶r̶t̶ ̶i̶n̶t̶r̶o̶d̶u̶c̶t̶i̶o̶n̶,̶ ̶a̶l̶t̶h̶o̶u̶g̶h̶ ̶I̶ ̶d̶o̶n̶'̶t̶ ̶t̶h̶i̶n̶k̶ ̶i̶t̶ ̶w̶i̶l̶l̶ ̶c̶o̶m̶p̶i̶l̶e̶ ̶o̶n̶ ̶t̶h̶e̶ ̶a̶l̶p̶h̶a̶ ̶d̶u̶e̶ ̶t̶o̶ ̶t̶h̶e̶ ̶u̶s̶e̶ ̶o̶f̶ ̶p̶r̶o̶c̶:̶ ̶h̶t̶t̶p̶:̶/̶/̶w̶w̶w̶.̶r̶u̶s̶t̶f̶o̶r̶r̶u̶b̶y̶i̶s̶t̶s̶.̶c̶o̶m̶/̶b̶o̶o̶k̶/̶c̶h̶a̶p̶t̶e̶r̶-̶0̶6̶.̶h̶t̶m̶l̶. See Steve's awesome documentation posted below!

Currently you need to type a bit more, but the compiler is able to make some channel usage errors uncompilable. I can see myself doing napkin prototyping in Go (as I already do) and writing the real version in Rust for better performance and safety in many cases.

> What’s a concrete problem Rust could solve for me? How about first class support for writing a GUI application?

Though I don't think GUIs need to be a primary focus, there are some useful projects already. The rgtk library [1] is the best so far. It is the first Rust project I contributed to. It is currently broken due to the changes in the language, but that should be fixed relatively soon. GTK is more natural to interface with than Qt or WxWidgets because it is written in C.

[1] https://github.com/jeremyletang/rgtk

I would love a programming language with first class cross platform GUI support. And by that, I mean native code with a web GUI. I was really excited about Elm for that reason, but the installation process is abhorrent and overly complicated. It'd be nice to write a program that runs on my local machine and presents its GUI through Firefox without needing to depend on a third party library or having to worry about writing HTML, Javascript, and CSS.
The best solution I've found for that is Clojure and ClojureScript. That combination allows you to create a single, self-contained jar file that runs a local web server and opens a localhost address using your default browser. From there, it serves the web app you wrote.

My IDE called Nightcode (see nightcode.info) has a template for that. You just click "New Project", give it a name, and then choose the "Web" template. It will generate a project that builds a single jar file like I described. Sorry for being off-topic but I figured it might be what you want.

Rust has always (well, for a VERY long time, multiple years) had a singular focus: memory safety without garbage collection. Early versions of the language had a lot of built-in features, but eventually, the core language was powerful enough to move them out.

Ironically, channels are a great example of this. Rust used to have a channel keyword, and the language used to reason about them directly, but nowadays, the type system is strong enough that they (and in fact, all of I/O) is just a library, yet just as safe.

Rust also has strong enough guarantees that channels aren't always as necessary as they might be in other languages. For example, we can catch data races _at compile time_, which means shared memory just isn't as dangerous. The type system makes it impossible to mess up your usage of things like atomics and mutexes.

Anyway, if people don't know what Rust is about, it's ultimately a failure of our marketing. We'll get there. :)

> The type system makes it impossible to mess up your usage of things like atomics and mutexes.

You can still cause deadlocks and livelocks in well-typed code, which I put into the category of "messing up your usage of mutexes". It would take a more powerful type system to prevent these errors. It is also unclear whether the behavior of mutexes in the face of task failure is correct for all use cases.

I think Rust prevents data races. That's pretty much the reason it has mutable variables. Compiler won't allow two places to borrow the same variable mutably.
I think what he meant is that the compiler gives you certain guarantees that in some cases will mean that you don't need to directly use atomics and mutexes at all. Rust still allows you to arbitrarily harm yourself, but it usually makes sure you are more clear about your intention to do so.
Well put! Rust shines in that these sorts of abstractions (channels being just one example) which must be builtin in other languages can be expressed as library types in Rust. It is a distinct strength, not a weakness as this article seems to imply.
I hope Rust gains traction as a language for targeting embedded systems. Rust has the following attractive characteristics for this particular domain:

* Minimal overhead (e.g. runtime), great for systems with very constrained resources

* More advanced language features than C (better macros, better type system, pattern matching, etc)

* Compile-time verification of safe usage of memory

* The ability to drop down into manual/unsafe mode for doing stuff like DMA or writing to configuration registers

c.f. this topic from a year and a half ago: https://news.ycombinator.com/item?id=6268291

I did a bit of embedded development (MSP430, Cortex M3, PIC18) some time ago, and I can say that having a language like Rust at my disposal would have drastically improved my productivity.

I presume you've seen https://zinc.rs/?

"Zinc is an experimental attempt to write an ARM stack that would be similar to CMSIS or mbed in capabilities but would show rust’s best safety features applied to embedded development."

There are a number of other important issues driving language adoption which were not mentioned in the article from the quality of the tooling and documentation to existing code bases (and consequently the quality of FFI). I'm also surprised python didn't get a mention given that this is where a large number of new Go programmers come from.

As for the languages themselves, I was very happy when Go came out and I've been using it for the last two years. I generally loud the conservative approach to language features that Go took, but I fear they've overdone it.

One feature missing from Go which is mentioned at every such occasion (and with a good reason) is generics. Their value to the programmer would be even higher in Go than in other languages, since a lot of existing concurrent code could be written in a generic way and reused regardless of what needs to be put in the channels.

There are also a few minor annoyances like lots of boiler plate (e.g. overly verbose for loops), nil pointer, no algebraic data types, select statement vs reflect.Select(), range keyword (off-limits to your own data structures).

I've got high hopes for Rust.

> First and foremost, transparent concurrency support with solid runtime support. Definitely a specific problem that developers have and definitely a concrete solution to that problem.

Hm, I think this is a bit distant from reality. People who use Perl/Python/Ruby eventually experience problems with performance and memory usage and start looking for alternatives. And since Go is a small language, familiar to everyone and offers an easy way to replace existing services (static binaries) - people choose it.

Ted meant that Go has a decent story for this particular use case, not that everybody uses it because of that. I think that you meant to say "distant from my reality" instead of "distant from reality", because otherwise your statement does exactly what you strawman Ted's into saying.
> not that everybody uses it because of that

He says "succeeded", isn't that the same thing you are arguing against?

Not quite, I am against the notion that everybody uses Go for one reason. But I also think that the reason you gave would not be true if goroutines and channels, or some other easy to use concurrency abstraction, were not a primary fixture of the language.
The Rust team knows better. Rust is not D, it's C. It is designed and dogfooded with a specific case in mind. C had killer app which was UNIX and Rust has Servo https://github.com/servo/servo

The majority of software can be written in python, Go, Ruby, Haskell etc. but the software that need to be native is extremely important. Improving browser parser by 10% improves millions of apps. Having better and more productive language is better for faster innovation.

My only problem with Rust is that the first version has a lot of features. The should have shipped 80% of them and add the rest in 2.0.

What's the point in making 1.0 if it's not forwards compatible? There were some very serious issues with the language, that if not addressed, would require rewriting code when they were fixed. Adding them in 2.0 would probably doom it.

It's not like 1.0 represents all the features they want though, there are many language and library features that are planned for the future.

I can't find any empirical evidence that adding features in the next version dooms the language. The opposite is true. All successful languages started small.
Python is being hurt by Python 3.0 changing so much.
By breaking backward compatibility. Not forward.
The changes that are currently being done in Rust for 1.0 are those kinds of breaking changes. Many things that are being changed have been in a state of semi-decay from old experiments, and old features of the language.

As an example, the IO subsystem had lots of generality designed for when lightweight tasks were still a feature. By ripping them out, the library is both easier to use, and simpler for future expansion. It was also changed to support the general error-handling facilities that Rust now has (which are partly similar to the old IO-specific error handling features, but wouldn't work well with other libraries).

Others like the collection-api cleanup were badly needed, because of inconsistency and a lack of direction over time. Now the collection-api is much cleaner, and consistent between different types of collections. This allows them to add things like collection-api traits in the future, and newer collections that can follow the same api conventions

Support of big companies is as important as the language itself. If D had a big player to push it or if Borland haven't went bankrupt or java wasn't pushed so hard by Sun, this list would look very different today...
For me, the biggest problem with this essay lies in this one sentence: "Memory safety could qualify as a targeted problem, though historically that’s been a tough sell on its own."

My question is: Who offered memory safety on its own, historically? I think the reason that memory safety has been a tough sell historically is that it always came with performance overhead and lack of low-level control, and people kept using C and C++ for low-level programming as a result. By contrast, Rust tries to go farther than any other industry language in truly providing memory safety on its own—without any of the baggage of JITs, or garbage collection/pervasive reference counting. If you had to sum up the raison d'être for Rust in one sentence, that'd be it.

I think that historically, memory safety "on its own" hasn't been tried, at least to the degree that Rust strives for.

Yes, a primary stated goal of Rust is "memory safety without garbage collection." I'm not aware of any other language for which this is a top priority.
It's because it's an extremely delicate balance (considering reference counting a form of GC, which it is): you have to carefully design the entire language around it in order to get the safe expressiveness that Rust provides. It'd be very hard to retrofit onto an existing design and match Rust's expressiveness.
How does Rust deal with reference cycles?
By giving you enough tools that referencing counting isn't what you reach for. If you do need it, though, we use weak and strong pointers.
Not to take away from anything you've said, but in some scenarios, GCs have a lower impact on performance than dynamic allocation (well, if you use dynamic allocation). For one, they provide better throughput -- their overhead is mostly much higher memory usage, and latency (occasional pauses, although "pauseless" collectors -- actually, short pauses of a few milliseconds -- are used in the industry). But their more interesting advantage is in concurrent data structures. Many lock-free data structures (actually, most of the interesting ones) require a GC, or techniques that are less performant, less general, or both, like hazard pointers and user-space RCU.
Rust has a different notion of memory safety than the Java or Go memory models. In fact, compared to Rust's memory model, both Java and Go are memory unsafe (in the Rust sense of safety, not the traditional sense)

Namely, Rust's notion of memory safety prevents data races in concurrent programs. This is because Rust's region typing / lifetime system rejects racy programs as invalid.

Go provides something more like a built-in concurrency framework than truly baking this sort of safety into the language. It's just as possible to write racy concurrent programs in Go as it in in Java, C++, or C.

Go provides idioms that can help you avoid writing racy programs, but they're just that: ideas about how to structure your program, not guarantees that will keep you from shooting yourself in the foot.

Go provides a data race detector so if you do write racy programs, you can retroactively detect the problem. Unfortunately data races have this nasty tendency to pop up under unusual circumstances like high load or unusual combinations of events.

That the author of this post chose concurrency as the thing to harp on about Go's superiority shows how little experience that person has with Rust, IMO. Rust shares the same basic concurrency concepts as Go (communicating sequential processes), but features a compiler whose type system prevents you from writing racy concurrent programs.

Rust's multi-threading most certainly is not CSP. CSP requires communication to be synchronous. Rust documentation states that send() will never block and channels have infinite buffer.

AFAIK, rust also doesn't allow selecting between a send and receive on channels. It only allows selecting over a set of receivers and even there it doesn't offer something like the default clause of Go's select statement.

Rust does have interesting features to prevent data races but it's concurrency model is very different from CSP and Go. Since the author praises Go's concurrency in the context of writing servers, it is entirely reasonable to prefer goroutines over OS threads as the unit concurrency.

Rust supports both synchronous and asynchronous message passing over its channels. It's true that asynchronous message passing is generally associated with actor systems and not specifically with CSP, but it's also seen in many extensions of CSP, and in fact CSP and actor systems are duals of each other.

Rust supports both approaches.

I was wrong about synchronous communication. Since most rust example use async channels, I missed the existence of sync_channel.

However, even if that exists, rust's concurrency doesn't follow CSP as much as go's. Like I mentioned in my previous comment, it doesn't have a way to do everything the select statement in go does. This is not necessarily a bad thing, but rust definitely doesn't share the same concurrency concepts as go. It offers everything that Java/C++ does along with data race protection.

Speaking of data race protection, the current type system rejects a lot of very common "non-racy" code too. There is work in progress to address some of them and may be most of them will be addressed eventually.

> doesn't follow CSP as much as go's

Because it supports asynchronous messaging too? As if CSP were some concept that emerged fully formed from Tony Hoare's head like Athena from Zeus?

I'm sorry you see dichotomies where others see dualities.

I was referring to select statement, not async messaging support.
You mean like the select! macro in Rust?
No the select statement of go. It is way more capable that rust's select macro.

The tone of your previous comment made me feel that this thread is going in an unproductive direction, so I'll stop here.

Considering you've backpedaled from "Rust isn't CSP" (because you misunderstood Rust channels) to "Rust doesn't have select" (which it does, and you didn't realize) to "Rust's select isn't as mature as Go's", that's probably for the best.

Perhaps you should try to be more informed about Rust before you try to have an argument about it in the future!

I said 2 things in very first comment. I never claimed rust doesn't have select. This is quoted from my very first comment in this thread,

AFAIK, rust also doesn't allow selecting between a send and receive on channels. It only allows selecting over a set of receivers and even there it doesn't offer something like the default clause of Go's select statement.

Perhaps you should try to read my comments in their entirety before making accusations.

Yes I missed sync_channel, but if that is all CSP was, Java does CSP too. It has Threads and SynchronousQueue exactly like rust 1.0 will.

I thought you were done? Apparently not!

This is where I again point out that neither Java nor Go ensure that state sent over channels is actually isolated, and both allow data races.

With Rust that is not the case. You have true isolation (unless you explicitly opt not to)

How can Java actually be safe when it is such a huge cause of constant security compromises that most security experts recommend disabling or uninstall in it?
The majority of Java CVEs are about ways by which sandboxed Java applets can escape the JVM sandbox (which is implemented in C++), which is a kind of error that is only possible in the very few language runtimes that can run untrusted code in a browser (like JavaScript and ActionScript/SWF).

If you run a Java application outside a web browser, e.g. a server-side application, it won't run untrusted code and it isn't sandboxed by the JVM (like any other language), so those CVEs are irrelevant in that case.

There's a lot of GC'ed languages out there to choose from. A language that makes it optional is not only more powerful, but can be used in places where GC is not an option.

IMHO, for GC'ed languages, Go is just more of the same. I can think of a bunch of languages that offer much more already.