
Thoughts on replacement languages - protomyth
http://www.tedunangst.com/flak/post/thoughts-on-replacement-languages
======
pcwalton
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.

~~~
kyllo
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.

~~~
pcwalton
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.

~~~
cpeterso
How does Rust deal with reference cycles?

~~~
steveklabnik
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.

------
steveklabnik
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. :)

~~~
cwzwarich
> 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.

~~~
krenoten
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.

------
austinz
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](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.

~~~
antiuniverse
I presume you've seen [https://zinc.rs/](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."

------
jeffdavis
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.

~~~
pron
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.

~~~
austinz
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](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.

~~~
krenoten
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...](http://channel9.msdn.com/Events/Lang-NEXT/Lang-
NEXT-2014/Panel-Systems-Programming-Languages-in-2014-and-Beyond)

~~~
mseepgood
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.

------
krenoten
"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.

~~~
steveklabnik
The official docs are pretty reasonable here: [http://doc.rust-
lang.org/std/sync/mpsc/index.html](http://doc.rust-
lang.org/std/sync/mpsc/index.html)

------
bascule
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.

~~~
tuxychandru
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.

~~~
bascule
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.

~~~
tuxychandru
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.

~~~
bascule
> 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.

~~~
tuxychandru
I was referring to select statement, not async messaging support.

~~~
bascule
You mean like the select! macro in Rust?

~~~
tuxychandru
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.

~~~
bascule
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!

~~~
tuxychandru
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.

~~~
bascule
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)

------
gw
> 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](https://github.com/jeremyletang/rgtk)

~~~
freehunter
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.

~~~
gw
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.

------
zzzcpan
> 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.

~~~
krenoten
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.

~~~
zzzcpan
> not that everybody uses it because of that

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

~~~
krenoten
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.

------
avz
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.

------
ivanhoe
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...

------
lukasm
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](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.

~~~
keeperofdakeys
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.

~~~
lukasm
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.

~~~
codygman
Python is being hurt by Python 3.0 changing so much.

~~~
lukasm
By breaking backward compatibility. Not forward.

~~~
keeperofdakeys
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

------
namelezz
In this video
([https://www.youtube.com/watch?v=BBbv1ej0fFo](https://www.youtube.com/watch?v=BBbv1ej0fFo)),
D, C++, Rust, and Go creators clearly explain what they mean by system
programming. From that, I believe Go is to Java, C#, Python, and Ruby whereas
Rust and D are to C/C++.

------
leovonl
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.

------
TwoBit
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_why_of_y
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.

