
On Rust Hate-Writing - Ruud-v-A
https://graydon2.dreamwidth.org/209581.html
======
lukego
I am impressed with Rust in many ways.

I briefly considered Rust when shopping for the right language for Snabb
Switch [1]. I decided against it in part because the community did a good job
of setting my expectations. "They" told me that Rust will especially appeal to
hardcore C++ hackers, which is a very different profile to our target group of
casual programmers. So I was able to move on quickly from a choice that really
would not have suited me, with no ill will along the way.

If for whatever reason I had been pressured to move ahead with Rust then I
would have spent a lot of time swearing about the size and compilation time of
LLVM, etc, before finally moving on to a tool that is better suited to the
peculiar job at hand.

So from my perspective that is great work by the Rust community - defining and
communicating who the target user is - and now I would certainly consider Rust
for other projects in the future.

[1] [http://lukego.github.io/blog/2012/09/25/lukes-highly-
opinion...](http://lukego.github.io/blog/2012/09/25/lukes-highly-opinionated-
programming-language-roundup-2012/)

------
zamalek
Holy hell that title. When did critique become "hate-writing?" I do mostly
agree with the article, though.

> If the person is spewing anger, try to minimize the harm done by that anger
> by either asking them to stop or removing yourself and others from observing
> or participating in it.

The fact that this is thought of the original piece and that people need to be
told not to get passionate about a _tool_ is deeply worrying.

> Imagine Rust was a kid you were sending to preschool.

No it's not. It's a tool. The problem here is that people are attaching
emotions to tools and code, as though they were their spouse or children.
Emotions are an irrational/illogical process, programming is rational/logical
- don't mix the two.

Rust is doing just fine, some criticism levied against it is healthy. The tone
of the criticism is completely irrelevant. Ignoring that _hurtful_ criticism
is merely going to do the _beloved_ tool harm in the long run - no matter how
much "<3" was put into it.

~~~
nightpool
So, the first thing to recognize is that everybody has feelings. This seems
like kind of an obvious and maybe a bit of a condescending thing to say, but
the fact of the matter is that when you pour your life into something over 4
years, you're not going to come out of it with a "rational/logical" process—no
matter what your ideal of programming is.

Is ignoring criticism a good thing? No, obviously not. But there's a wide gulf
between constructive criticism and posts like the one being obliquely
referenced here[0]. When an author makes only the most cursory effort to
examine a language, and then pronounces it inferior to what they prefer with
only very vague (and in many cases flat out incorrect) arguments, I think its
safe to assume that they're not doing it out of the kindness of their heart.

[0]: [http://www.viva64.com/en/b/0324/](http://www.viva64.com/en/b/0324/) in
case you missed the comment downthread

~~~
zamalek
"You are not your code"[1]

When I look at code I wrote in the past I frequently think "what utter horse
shit." I'm a better coder than I was 4 years a go and I will be a better coder
in 4 years time. The extension of that means that, yes, the code I write today
will be terrible by the standards of my future self. So yes, I am right now
writing terrible code and it's _fine._ If someone takes the time to critique
my code maybe it will be less terrible and in 4 years time I will be proud of
it.

This doesn't mean you can't take pride in what you do.

> I think its safe to assume that they're not doing it out of the kindness of
> their heart.

Valuable criticism is not determined if it was done by the kindness of
someone's heart. Your most valuable critique can often come from your worst
enemy. You might have to read between the lines/vitriol but there is gold in
there somewhere.

[1]: [http://sstephenson.us/posts/you-are-not-your-
code](http://sstephenson.us/posts/you-are-not-your-code) \-
[http://www.hanselman.com/blog/YouAreNotYourCode.aspx](http://www.hanselman.com/blog/YouAreNotYourCode.aspx)
\- [http://blog.codinghorror.com/egoless-programming-you-are-
not...](http://blog.codinghorror.com/egoless-programming-you-are-not-your-
job/)

------
derefr
> Technical and human pluralism enriches the world. Monocultures do not.

Unlike human culture, tech cultures can't communicate to enrich one-another.
(The people _in them_ can, but this is a different thing.)

To explain what I mean: you can't import a Ruby library into a Python program.
You _can_ import a C library in a Rust program, or vice-versa—but that's a
special case. Even then, you can't _write a patch for_ a C library in Rust, or
vice-versa, because the original maintainers of the library you want to
contribute to are only going to accept contributions in languages they
understand and can maintain directly.

I really believe that fixing this—decoupling "runtime/platform" from "language
semantics", and "language semantics" from "syntax"—is the single most
important thing that will happen in software engineering in the next 20 years.

Imagine a program somewhat like go-fmt(1), that would run on checkout of a
source repo, to transform a base-level AST into the syntactic representation
of your choice, and pattern-match-decompile any low-level statements with
high-level "shape" into the macro-statements in your chosen language that
would generate them[1]. Imagine every library being not only available in
every language, but able to be contributed to by programmers who know any
language. Etc.

The result would be, in one sense, a "monoculture"—a single ecosystem of
libraries, rather than 12 ecosystems between the CRT, the JVM, the CLR, the
Erlang VM, etc. But it wouldn't disallow competition between versions of said
libraries—just allow obvious winners to win once-and-for-all, instead of
limiting their success to their technological "country of citizenship."

\---

[1] Or, better yet, a FUSE server where an underlying directory of AST files
gets mounted as syntaxified files. Much cleaner from the rest of the
toolchain's perspective.

~~~
pron
Unfortunately, that's not how languages work. There may be language
equivalence classes (that would put, say, Ruby, Python and JS in the same
class, C, C++ and Rust in another, and Java, C# and Go in a third), but
languages from different classes can't just be translated from one to the
other. First, a program written in one language isn't just a description of an
algorithm, but a description of the algorithm plus language-specific
information that's supposed to help the particular platform execute the
algorithm efficiently. Second, there are essential runtime differences that
can't be easily ported, such as a threading model and a memory model -- and
those may significantly affect the suitability of an algorithm for a certain
language. Finally, there are fundamental differences in the appropriateness of
certain algorithms; specifically, imperative algorithms can't be automatically
translated to pure-functional algorithms without possibly changing their time
and space asymptotic complexity.

In short, there's a lot more to a computer program than a description of an
algorithm, and even algorithms vary considerably in their suitability
depending on the language/runtime executing them. Even if you could solve the
first problem, you're still left with the second.

I do agree with the premise, though: unless your new language/runtime is so
revolutionary that it reduces development cost _dramatically_ , fracturing the
ecosystem is often too high a price to pay for merely a "nice" improvement.
The problem is that many languages claim dramatic cost reductions, but it
usually takes years to learn whether or not they deliver. The reason for that
is not just the number of data points, but the fact that the cost of software
is spread across a codebase's lifetime (10 years is about the average lifespan
of a production system codebase), and how development looks -- and what
activities contribute to costs -- in the first and second year is very
different from how it looks in the sixth.

~~~
derefr
> but a description of the algorithm plus language-specific information that's
> supposed to help the particular platform execute the algorithm efficiently

Tracing JITs should be able to spit out, as they run, the tables of Bayesian
confidences they've built up for various static properties of the code, which
can sit along with things like source maps, and be confirmed/rejected by the
programmer in their IDE, or just live-reloaded into a new VM ala a Smalltalk
image. (Future-tech, remember.) You can see the potential for this in things
like Erlang's typer+dialyzer system.

Likewise, static analysis tools should be able to work on foreign code after
transpilation. There's nothing stopping you from transforming C code into Rust
code in order to get the Rust compiler's opinion on its ownership semantics.

Note that I'm not saying that there's one universal underlying language
semantics. Just that language semantics (which consist of such things as a
type system, a threading/memory model, etc.) have no reason to be tied to
either a particular syntax, or a particular VM. (Effectively, a language
semantics forms an _abstract machine_ that executes more or less efficiently
on the substrate of any given VM. MRI Ruby is a direct substrate for Ruby
semantics; IronRuby is less-clear substrate; etc.)

> those may significantly affect the suitability of an algorithm for a certain
> language

This is a problem of transparent distribution. I've been working on an Elixir
DSL for writing Haskell "inside" Elixir for efficiency. The result is not a
Haskell compiled module getting linked into the Erlang VM, but rather a
separate Erlang-VM-managed Haskell "application server" being run as a port
program. I foresee much more of this, and much more cleverness about it:
writing code that compiles to a bunch of separate modules _for separate VMs_ ,
which then form a micro-distributed-system all within a Docker container or
somesuch.

Again, it's not about eliminating the plurality of runtimes—it's about
rendering that plurality _moot_ , abstracting it away from the perspective of
the programmer and leaving it up to the implementation to decide how to
optimize abstract-machine-to-VM allocation.

There's no reason that you can't have every language semantics available to
any library, to use in any combination (this parameterized type system with
that green-threading and this other GC, etc.) It's just that, in so doing,
you're either transparently importing into your single runtime some
virtualization layers for all the other abstract machines you've coded in
terms of (somewhat like writing a Windows app on Linux by linking it to Wine),
or you've let the Sufficiently Smart Code-generator go beyond the premise of
having a single target platform.

~~~
pron
> Future-tech, remember.

Not so much future tech. The most sophisticated JIT in production use nowadays
is HotSpot's optimizing JIT, and next year it's getting this:
[http://openjdk.java.net/jeps/165](http://openjdk.java.net/jeps/165)
(basically, metadata that the programmer can use to help the JIT with some
decisions). HotSpot's next-gen JIT, Graal, takes five more steps forward and
allow a full programmer-controlled JITting, that can suggest and improve
various speculations on the semantic AST:
[https://wiki.openjdk.java.net/display/Graal/Publications+and...](https://wiki.openjdk.java.net/display/Graal/Publications+and+Presentations)

I have full confidence in the general utility of JITs for server-side
applications, but JITs themselves are a tradeoff (require warmup or caching,
more RAM and more energy).

> There's nothing stopping you from transforming C code into Rust code

Not really, because Rust requires manual type annotations. Either they are
added manually -- in which case you may as well translate manually -- or
automatically, in which case the tranlator would need to infer the very same
properties you want to verify.

> Just that language semantics (which consist of such things as a type system,
> a threading/memory model, etc.) have no reason to be tied to either a
> particular syntax, or a particular VM.

But they do because it's not just syntax -- the language and runtime are
really a part of the algorithm (in fact, most algorithms presuppose a certain
execution context like random, constant-time access to memory). The
threading/memory model is what determines whether certain algorithms can be
implemented at all; functional purity can completely change the complexity (by
more than a constant) etc.

> I foresee much more of this, and much more cleverness about it: writing code
> that compiles to a bunch of separate modules for separate VMs, which then
> form a micro-distributed-system all within a Docker container or somesuch.

The problem with that is that once you go distributed (even on the same
machine) there are _tremendous_ performance costs involved. Not only
marshalling/demarshalling of data, but fanning-in and then fanning out your
concurrency on each end. There's no way you can use, say, a Java parallel
stream, whose parallel operation is performed over the wire. There are only
very specific places where you can place that boundary.

I do, however, think that a platform such as OpenJDK, with such powerful GCs
and JITs, can -- and indeed does -- contribute significantly to the ability to
interoperate among various languages -- but certainly not all of them.

~~~
derefr
> But they do because it's not just syntax -- the language and runtime are
> really a part of the algorithm.

I don't think you understood my statement above—what you're attributing to the
runtime (memory-model et al) is part of the abstract machine specified by the
language's semantics, but that's _orthogonal_ to the runtime.

A runtime can be a better or worse _fit_ for a given language's semantics, but
any VM can virtualize any abstract machine with enough glue. VMs are Turing
machines, after all. (In practice, the overhead can be surprisingly low; you
don't have to emulate what you can trace or dynamically recompile. The work
around ASM.js is rich in data about how to squeeze performance out of the not-
particularly-direct mapping of the C abstract-machine to the JS VM.)

The abstract machine formed by the language semantics can, of course, demand
live support machinery of the underlying runtime (like a GC, say) that may
have to be "polyfilled." This is what we've been doing forever—a PIT
signalling a processor interrupt which is checked for between each cycle is
just a polyfill for having concurrent processes on other processors sitting in
blocking-sleep for a bounded time, for example. Any hardware emulator is full
of these. Usually you can find ways to make them less necessary—IronRuby
doesn't contain its own GC with Ruby semantics, it just translates Ruby's
GCing requirements into calls to the CLR allocator+GC and the result works
"well enough."

> Not only marshalling/demarshalling of data, but fanning-in and then fanning
> out your concurrency on each end.

Why are you assuming message-passing distribution? Shared-memory cross-runtime
distribution works too. That's how ZeroMQ works, for example.

~~~
pron
> what you're attributing to the runtime (memory-model et al) is part of the
> abstract machine specified by the language's semantics

OK, I see where you're going with this. But now you'll need a "bottom
representation", which, even if it is easier to transform than machine
instructions, will be pretty hard to decompile to another language. For
example, most interesting lock-free algorithms require some sort of garbage
collection; how do you describe that GC behavior, which doesn't necessarily
need to be general purpose, in a way that can be ported to both C and Go?)
Theoretically it may be doable, but in practice the problem is very, very
hard.

The big question, then, is why bother? The JVM already provides excellent
interoperation with excellent performance that can cover the vast majority of
(at least) server-side applications out there, and Graal/Truffle are extending
the range of languages that the JVM can provide the fastest implementation for
(it's early days and it's already pretty much on par with V8 when running JS,
and faster than PyPy for Python). Those applications not within this profile
range will use other languages (like C++), but those languages are already
more expensive to develop in, and their developers happily pay more for more
specialized algorithm implementations.

> Shared-memory cross-runtime distribution works too.

That's true (provided both sides can agree on an ownership and concurrency
behavior).

------
kibwen
For those lacking context, these remarks from Graydon are likely a response to
the following post which has been trending today, though it didn't get much
traction on HN:
[http://www.viva64.com/en/b/0324/](http://www.viva64.com/en/b/0324/) (with
some comments at
[https://www.reddit.com/r/rust/comments/35pn5a/criticizing_th...](https://www.reddit.com/r/rust/comments/35pn5a/criticizing_the_rust_language_and_why_cc_will/)).

~~~
MichaelGG
Heh. "People are idiots" ... "C++ doesn't restrict programmers".

Seriously though, the article was just negative with not a whole lot of real
points. It's also amusing to see C++'s more and more convoluted codegen (see
the VS2015+ObjV video) to make up for fundamental mistakes users keep making
no matter what.

I can see how this might be discouraging, but I'd take it as a good thing if a
poor rant is all they got.

------
nemothekid
"There are 2 types of programming languages, those everyone complains about
and those nobody uses..."

I look forward to Rust's version of "Go sucks because Generics"

------
djhworld
This happens whenever a Go post crops up on HN too, the amount of vitriol some
people have over a language they evidently don't want/need to use is shocking.

------
tempodox
I don't cope well with light text on dark background because it hurts my eyes.
And I haven't personally encountered Rust hate-writing yet, as the author
describes it.

Apart from that, I recommend this text to everyone. If you find yourself in a
situation that feels conflict-shaped, read this text before you crawl up the
walls. It's good advice.

------
rational_indian
Awesome post! A minor typo in the first paragraph: change Each to Every.

------
steveklabnik
Wonderful as always.

