
Still in love with Rust - adamnemecek
https://dpc.pw/still-in-love-with-rust
======
vaylian
> Rust will force you to be a good programmer,

> [if] you like it or not.

This is probably the best in-a-nutshell statement that describes what a good
programming language is for me.

I had similar moments in the past. Before Python I cared about indention to
some degree. But once I got used to the way Python forces you to indent your
code, I came to the realization that this is pretty much the way I should
format my code anyway and it influenced my coding style in all other block-
based languages for the better.

Clojure was another language that showed me how functional programming should
be done. My code in all languages changed and I used a lot less variables and
a lot more constants and parameters. My code and the systems I created became
a lot simpler and much more robust as a consequence. I had used Haskell before
but it never really transformed my mind the way Clojure did. I also got a
really good grasp on destructuring and list comprehension.

Rust offered me several relevations. I finally understood test-driven-
development because the language has excellent support for it. I also
understood RAII more deeply. Traits became clear to me (Clojure protocols and
Haskell type classes felt strange to me). I finally understood why the Maybe
monad in Haskell/ML is one of the simplest and yet bests ideas in programming.

And there is the borrow checker. I already had a functional programming
mindset when I picked up Rust. But having a clear owner of data takes the
mindset of functional programming even further[1], even when mutability is
involved. It is a lot easier to reason about your code when you know exactly
which operations can (and should) change a variable.

An aspect that the Python, Clojure and Rust communities have in common is that
they emphasize idiomatic code a lot. Therefore it is much easier for newcomers
to find examples of professional-level code and learn things the right way.
And it is much easier to dive into a new codebase. Clojure is actually a very
extreme case of this, because Clojure code tends to use a lot of 1-letter
parameter names. In most programming languages you are allowed to have the
variable "i" for looping over numbers. But not much more. In contrast, Clojure
has a list of well-established 1-letter variables that are recognized by
everyone in the community.

[1] This does not adhere to the classical definition of functional programming
but I feel that it is a natural extension to it.

~~~
sifoobar
Only as good as Rust allows you to be, which is fine for some until they
stagnate or grow out of it; but far from the final answer to anything.

I don't get at all how being forced to do anything could ever be a good thing.
Smells like cognitive dissonance from here. I'm all for powerful tools that
enables me to write better code faster; but being forced, really? That's the
best thing about Rust? Ew.

~~~
knocte
> I don't get at all how being forced to do anything could ever be a good
> thing

If you don't prefer tools that can automatically check if you were a good
developer or not, it not only does not scale (to trust the software you
build), it's that I wouldn't want to work with you as a teammate.

~~~
sheepmullet
> If you don't prefer tools that can automatically check if you were a good
> developer or not

You are pretending there are no trade offs.

> it not only does not scale (to trust the software you build)

I think we should all be able to agree that empirically that is nonsense.

~~~
GolDDranks
I have empirically witnessed that the larger a project gets, the harder it is
to trust that the code does the thing you want it to do. It's far from
nonsense.

~~~
sifoobar
True, regardless of language.

~~~
catach
Indeed, yet different languages seem to have different slopes.

------
hbbio
Rust is a wonderful language, but I still have the impression that it is not
stable as of 2018. All the toys I've made to play with it during the last
years went deprecated quickly, especially if you rely on the ecosystem of
packages (web server, database, ...).

In addition, there was this thread: [https://internals.rust-
lang.org/t/concerned-about-rust-2018-...](https://internals.rust-
lang.org/t/concerned-about-rust-2018-stability/7932)

All in all, Rust _will_ be great when stable (including the ecosystem).

~~~
simias
What do you mean by deprecated? Unsupported dependencies? All the code I've
written post-1.0 still compiles correctly (although a lot of it could use an
update to use new language capabilities).

I even have a bit of Rust in production at work and I haven't encountered any
maintenance issue so far.

Now the ecosystem itself can move pretty fast depending on the dependencies
you use, that's true, but that's a different issue. You're never forced to
update if you don't want to, you code keeps compiling with newer Rust
releases. Compared to most languages I've experienced with, Rust has been
_very_ stable post-1.0. And they seem to take that issue very seriously.

The thread you linked might have some truth in it but it seems like the main
point is "look, you've had a .2 patch release!" That's not a good thing of
course but unless you happened to jump on that new functionality as soon as it
got released the impact is rather minor and bugs happen.

~~~
sheepmullet
> Now the ecosystem itself can move pretty fast depending on the dependencies
> you use, that's true, but that's a different issue.

Is it? I’m used to languages which bundle a huge set of standard libraries as
part of the language.

------
EugeneOZ
"No race conditions, leaking resources, dangling pointers, unhandled
exceptions, ..., the list goes on."

Except of dangling pointers, Rust has everything else from this list.

About compilation time issue: it doesn't exist anymore. Current versions do
"cargo check" in a few seconds even for big projects (my biggest project is
45k LoC) and it takes a couple of minutes to compile it because of incremental
compilation. For libraries it takes seconds to compile and 1-2 seconds to run
"cargo check" (or clippy).

~~~
Laaas
It is indeed true that you can unintentionally leak resources, but it is still
much harder. Also, what do you mean that it has unhandled exceptions and race
conditions? Rust doesn't even have exceptions (although there are panics,
which is not the same thing), and race conditions are statically prevented in
safe code due to how a mutable reference works.

~~~
EugeneOZ
Theoretically they are different, in practice they are the same (it's just
more difficult to handle panicking - sometimes you can't use catch_unwind
because of it's trait limitations).

About race conditions: [https://doc.rust-
lang.org/nomicon/races.html](https://doc.rust-lang.org/nomicon/races.html)

~~~
setr
I feel like its quite difficult to call them the same in practice, when they
serve very different roles: errors that are likely to be recoverable are _not_
panics! in a sane rust api, whereas they very much are exceptions in sane C++.
You recover from either in similar fashion, but panics! are intended to serve
a much different role than exceptions (the common usage of exceptions in C++
being covered by Result<> in rust).

~~~
EugeneOZ
I hate when people use __exceptions __for __regular __errors, it triggers me
hard. Please let 's don't start this topic :)

~~~
speedplane
You started it.... exceptions are mostly annoying because they are so verbose.
Writing try... catch... is a whole lot longer than "if func() == null".

~~~
setr
Exceptions are mostly annoying because they’re infectious, and somewhat
undocumented (they’ve not part of the api; if an upstream library adds a new
exception, all downstream code must now handle it [or document it]), and if
anyone misses the update, its a runtime error waiting to happen. But notably,
your compiler won’t say a word about it (unless its java, in which case you’ll
probably get too much :-). Return codes are similar, but less cascade-y. Try-
catch being verbose and fucking up control flow is just an added bonus.

~~~
speedplane
Which is easier:

try: module.find_element() except: # handle not found else: # handle found

Or this:

if module.find_element(): # handle found else: # handle not found

------
onhn
“Bad programmers worry about the code. Good programmers worry about data
structures and their relationships.”

I think this hits the nail on the head for me: abstract structure first, the
choice of language C/C++/Rust/... is then a secondary consideration.

~~~
a_imho
Which brings up the question when/why to pick Rust? There are a plethora of
languages which from my layman perspective seem more interesting. OTOH there
are a plethora of languages with rich ecosystems, proven pedigree and with a
high demand for such developers.

~~~
seren
I am working on medical devices, where a bug can have catastrophic
consequences.

Essentially the ecosystem today is C and C++ for embedded FW and middleware.
Even if we are careful, we rely on static analysis tools to avoid some
categories of bug. (Plus a humongous amount of tests). Typically bugs that
would be caught (mostly) by the Rust compiler at compile time. I think it is a
great idea to have some safety guarantee at compile time.

Would Rust fixes every problem ? Absolutely not, you'll always get logical bug
or implementation not conform to the requirements but I think it is a move in
the right direction, and I hope that slowly in next 10 years Rust will grow in
the embedded space.

And overall cargo is nice, C/C++ don't have standard package manager. The test
infrastructure is there by default, this is a breeze to add them in your code,
rather than relying on an external framework, so this is also good.

I don't really see an alternative today for small footprint SW where C and C++
is king, and I hope that embedded toolchain vendors are taking notes.

If today you mostly code in javascript or python, unless you need bare metal
like performance or to have stronger safety guarantee, maybe it does not make
sense to move to Rust.

------
inamberclad
I'd still love to see a good tutorial on setting up Vim to work well with rls
and all the other plugins. I only really keep VSCode around since it works
with rls and sometimes I want to use the autocomplete for codebases that are
large enough to really need good autocomplete, but not so large that rls gets
bogged down and doesn't work at all anymore.

~~~
mcjiggerlog
For language server autocompletion, install coc.nvim -
[https://github.com/neoclide/coc.nvim](https://github.com/neoclide/coc.nvim)

Then

    
    
      :CocInstall coc-rls
    

and should work out of the box.

I also use [https://github.com/w0rp/ale](https://github.com/w0rp/ale) to
provide linting. Also works out of the box.

You can get these things running on vim8, but honestly it's easier to just use
neovim.

If it's of any use, you can check out my full config at
[https://github.com/tom-james-watson/dotfiles](https://github.com/tom-james-
watson/dotfiles).

------
LukaD
The comment about "no race conditions" is not accurate. Rust guarantees an
absence of data races which are not the same as race conditions.

[https://doc.rust-lang.org/nomicon/races.html](https://doc.rust-
lang.org/nomicon/races.html)

------
arendtio
> Barriers to entry

So far I had two faltering attempts to learn Rust but somehow I didn't find
good enough material to get me hooked.

I am looking for something similar to the Tour of Go[1], where you can
interactively try the language by solving minimal tasks. Does someone know of
such material?

[1]: [https://tour.golang.org](https://tour.golang.org)

~~~
steveklabnik
[https://doc.rust-lang.org/rust-by-example/](https://doc.rust-lang.org/rust-
by-example/)

~~~
arendtio
That looks pretty good. Thanks :-)

------
jerrre
> Let's face it – typically developers are familiar with OOP, garbage
> collected, dynamic programming languages.

I think most of these programmers, and their project are not the target of
Rust? If you're writing Java/C# or higher level languages, you already made
the choice to sacrifice some computing efficiency for programming efficiency.

I always thought Rust was more destined to convert C and C++ (and D/Swift/Go
?) programmers, that need the raw power and control.

~~~
steveklabnik
We have three major audiences:

* "systems programmers", aka the C and C++ folk

* "functional programmers", largely Haskell folk

* "scripting programmers", mostly Ruby/Python/JavaScript folk

Each has gotten something out of Rust, and also brought some things to Rust.

~~~
int_19h
You're missing the group which Java, C#, Swift, D and Go co-inhabit. Somewhere
between "systems" and "scripting".

~~~
steveklabnik
I did say "major" for a reason :)

I don't personally hear from many self-identified Java/C# people who are
coming to Rust. Maybe they exist and I don't hear from them, or they don't
describe themselves as such.

There are _some_ Go developers, but it seems the languages attract very
different types of people, so there aren't many. There are some people who do
love both.

There are only a few people from D (of which technically if you squint I'm
sort of one, incidentally.)

------
Svip
Thank you for this piece. I am working on a game, that I am prototyping in Go.
In my prototype, I have just entered the realm of multiple threads, and for
this project to work out, it needs to handle quite a lot of threads working on
the same resources.

While I have not personally dappled this far into concurrency in Go myself, I
have read plenty of articles where developers recommend using the mutex
package rather than the goroutines themselves.

But I've also read about Rust's thread and resource handling -- and I'll
admit, I've been looking for an excuse to write some Rust again -- and so
inspired by this entry, I've decided to finish the prototype in Go, and build
the real version in Rust.

~~~
monocasa
There was a great talk recently about how to properly build an entity
component framework in Rust if you haven't seen it yet.

[https://youtu.be/aKLntZcp27M](https://youtu.be/aKLntZcp27M)

~~~
Svip
Thank you for that link. Very useful. It already highlighted a solution in
Rust for a problem that I've run into with my Go prototype. And I appreciate
there also was a blog post to read.[0] I personally prefer articles over
videos.

[0] [https://kyren.github.io/2018/09/14/rustconf-
talk.html](https://kyren.github.io/2018/09/14/rustconf-talk.html)

------
insulanian
Can someone familiar with both Rust and F# (or OCaml) type systems write few
words about the expressiveness aspect of the language?

What would I miss in Rust if coming from the F# background?

~~~
steveklabnik
Fun fact: Rust was originally implemented in OCaml, and takes a lot of
inspiration from it. Rust was originally described to me by someone as "C
meets OCaml."

The biggest thing missing in Rust that are in both are higher kinded types.
The biggest thing missing from OCaml is parameterized modules.

~~~
insulanian
F# doesn't actually have HKTs either, unfortunately.

~~~
steveklabnik
I thought it did, my mistake!

------
geo_mer
Native async/await support is really great. I haven't gotten very far with
Rust but it already made me rethink many things that I thought I had
understood.

------
leni536
I tried Rust a few weeks ago. Is my understanding correct that Rust doesn't
have the equivalents to the following C++ features yet?

\- non-type and template template parameters

\- constexpr functions

I understand that Rust macros can replace them some of the time, and they are
much better then the C preprocessor, but that's quite a low bar to meet. Last
time I checked non-type template parameters (called "const generics" in Rust)
is on the roadmap, so it is promising.

~~~
steveklabnik
The equivalent of "constexpr functions" has a design, and is usable in
nightly.

The equivalent of "non-type template parameters" has a design, but is not yet
implemented. It's being worked on.

There's no direct design for the equivalent of "template template parameters",
but a similar feature has a design, but is not yet implemented. It's being
worked on.

------
kungtotte
Another point against Rust is binary size.

If you write the Fibonacci generator in one of the first chapters of the Rust
book it will create a 4MB binary. Even stripped it's over 400KB.

If you write the same code in Nim it compiles down to 112KB with debug
symbols, unstripped. Statically linked against libc (still with debug symbols)
it's only 850KB.

850KB statically linked versus ~450KB dynamically linked _and_ stripped.

For code that is virtually identical.

~~~
danieldk
Rust binaries include jemalloc. However, jemalloc is removed in nightly and by
default Rust will use the system allocator:

[https://internals.rust-lang.org/t/jemalloc-was-just-
removed-...](https://internals.rust-lang.org/t/jemalloc-was-just-removed-from-
the-standard-library/8759)

This should reduce binary sizes quite a bit.

~~~
vesak
And some rough numbers, rustc-1.30.1 vs rustc-1.32.0-2018-11-21, building a
hello world with --release...

Mac OS:

\- 1.30.1 before strip: 573K, after strip: 380K

\- 1.32.0 before strip: 267K, after strip: 178K

Ubuntu 18.04 LTS:

\- 1.30.1 before strip: 3.9M, after strip: 407K

\- 1.32.0 before strip: 2.3M, after strip: 191K

~~~
kungtotte
I'm on Void Linux right now running Nim 0.19 compiling the following code:

    
    
        when isMainModule:
          echo "Hello World"
    

_nim c hello.nim_ :

Before strip: 113k

After strip: 92k

 _nim c -d:release hello.nim_ :

Before strip: 79k

After strip: 63k

 _nim c -d:release --opt:size hello.nim_ :

Before strip: 46k

After strip: 30k

Kind of a toy example but it illustrates my point. An unstripped version of
the Nim program with full debug symbols is still 78k smaller than the
stripped, release version of the Rust equivalent. But it's great that they're
trying to work on this problem.

~~~
vesak
>But it's great that they're trying to work on this problem.

I don't know how the Rust team thinks, but I believe that minimizing binary
sizes is not a very big priority for them. The cost of a gigabyte these days
is, ~0.01$ (or less) for local hard drives, $0.4 for NVME and about $0.1 for
AWS EBS...

Technically of course it's cool how small Nim binaries are, and it does make
certain things feasible which with larger binary sizes might be difficult.

~~~
steveklabnik
We think it's important to be able to control it if you need to, and have done
work to make that possible. But we don't worry about the default _too_ much,
as you say, we've got a lot of things to worry about, and it's not near the
top of the list.

That said, the smallest executable produced is 145 bytes:
[https://github.com/tormol/tiny-rust-
executable](https://github.com/tormol/tiny-rust-executable)

------
axilmar
The moment a programmer conflates OOP with 'complicated graphs with lots of
interdependencies between nodes', it's the moment I stop reading their
writings.

OOP does not force one write complicated graphs of objects. OOP has its
applicability, FP has its applicability and well-written code in conventional
languages is a mixture of those two.

------
millstone
> Now I see how before Rust I was often writing my code in a typical OOP-way:
> forming complicated graphs, with many objects referencing each other, with
> unclear relationships. The class APIs, inheritance hierarchies, were there,
> but they were just obstructing the core problem: structuring and
> manipulating data... Rust will force you to be a good programmer, you like
> it or not.

Rust today demands static knowledge of all relationships. But class APIs,
inheritance hierarchies, and the like are powerful tools for dealing with
_dynamic_ relationships: code that runs together yet evolves separately, where
Rust is feeble. Good programmers recognize that different problems require
different solutions!

~~~
Dowwie
Rust is feeble at patterns it wasn't made for (OOP), absolutely. :).
Composition over inheritance.

------
Dowwie
Rust core development is working on many important features in parallel. The
feature I have been most excited about, and wish was here already, is
async/await. I wrote quite a bit of asyncio using futures and it was a bloody,
exhausting experience. Lack of documentation or examples made the experience
even more challenging. Much of what I wrote _could_ be trivially refactored to
async/await syntax, but I may keep some around to honor hard-earned gains.
It's not clear to me yet whether the first stable release in Q1 2019 will
allow me to port everything but I look forward to finding out.

------
Dowwie
dpc, the author, is such a helpful, positive force at the #rust-beginners IRC
channel

------
snrji
Rust still lacks an effect system, though. Any plans?

~~~
steveklabnik
No current plans.

------
purplezooey
_Bad programmers worry about the code. Good programmers worry about data
structures and their relationships._

Mildly horse shit. It takes both on a team.

------
woile
How does data-centric work? How is it different from OOP? Can someone
elaborate for a person using python?

Also, what opinion rust devs have over golang?

~~~
steveklabnik
> How does data-centric work? How is it different from OOP?

Rust doens't have objects. You have structs, which are purely data, and
functions, which are purely behavior. OOP puts the two together. So in Rust,
you don't _tend_ to design things by saying "what are the objects I need?" but
rather "what is the data I am manipulating and how do I manipulate it?"

> Also, what opinion rust devs have over golang?

I am not 100% sure what you're asking here, could you maybe re-phrase? Are you
asking why Rust is better than Go?

~~~
woile
Oh nice, good to know.

> Are you asking why Rust is better than Go?

No, just the opinion in general, why rust over go? I know go is more oriented
to distributed systems, but it seems like rust eventually will be used for
that as well. And I also see golang being used to build just anything, like
gopass for example.

~~~
steveklabnik
Ah. That's a more interesting question, for sure. :)

I got involved with Rust over Go because if I'm going to use a statically
typed language, I need generics. That was the initial thing, but other things
ended up going similar ways (I think package management is extremely
important, for example.)

I think Go has made great choices to accomplish its goals, but I'm personally
more interested in a different set of tradeoffs.

------
hasahmed
Rust sounds like the dream. I gotta check it out sometime

------
jjgreen
I was going to try out Rust, then I saw this on the download page

    
    
      curl https://sh.rustup.rs -sSf | sh
    

Really?

~~~
steveklabnik
Yes.

The script is less than 400 lines, and is pretty easy to audit. We wrote it in
such a way to prevent some issues like "if the download gets cut off only part
of the script gets run." It's served over HTTPS.

You can also probably get an install from whatever package manager you use, if
you prefer that.

~~~
tpxl
You can detect whether the script is being piped into sh, so downloading the
script via for example FF might produce different results than piping it to
shell, making audits useless.

~~~
steveklabnik
Sure. If you're worried about that, it's easy enough to download it first, and
then run it, without the pipe.

If you're auditing it, you've already downloaded it, so it's unclear to me why
you'd re-download and pipe rather than just running it.

~~~
nimmer
You still have zero guarantee that other people are getting the same code.

Encouraging people to run code from some random URL on the Internet is always
bad.

------
z3t4
Can't have a Rust post without a mention of D.

------
Vogtinator
Am I the only one who really can't stand rust?

I was and still am very much in favor of the ideas and concepts, but when I
actually tried to use it my opinion on it turned by 180°:

\- The syntax is awful \- No dynamic libraries \- Slow compile times \- Many
checks are too stupid to figure out some valid cases (maybe that improved
meanwhile)

~~~
steveklabnik
You are not.

\- No dynamic libraries

This is _technically_ incorrect, but practically correct, by the way.

> (maybe that improved meanwhile)

The next version, released on December 6th, ships "non-lexical lifetimes",
which does make the borrow checker smarter.

