
Rust can be difficult to learn and frustrating, but it's also very exciting - pauldix
https://www.influxdata.com/blog/rust-can-be-difficult-to-learn-and-frustrating-but-its-also-the-most-exciting-thing-in-software-development-in-a-long-time/
======
ilovecaching
Rust is the answer to the question "can we have speed, correctness, and
expressiveness in one language?" My company has been running Rust in
production for awhile now, and it's exceeded every expectation. It's fast,
it's safe, and it's so productive it's hard to find a reason to use anything
else.

We've also found that the learning curve is, in our opinion, a bit overstated.
We've ramped up several new grads on Rust with the O'Reilly Rust book. We see
real productivity in about two weeks, which is actually faster than it was to
ramp them up on our C++ code base. The compiler errors are _amazing_ and it's
almost like giving them a built in tutor.

I'm very bullish on Rust becoming _the_ language of choice in the 2020s for
everything from operating systems, web services, desktop applications, and
more. It's that good.

~~~
rqs
I think the learning curve thing is depends on what's the language that you
are compare it with.

C++ for example, is a hard language, but the learning curve is ... progressive
(rise bit by bit).

Rust on the other hand, is like climbing a cliff: You're exposed to everything
as soon as you start learning. That's all the Rust things (memory safety model
and borrow etc) plus the rest of the knowledge that you need to learn when you
normally learning a language (std library & stuff).

Luckily though, Rust did many thing in later years made it a little bit easier
to use and learn. Like the rewritten books and manual and in my opinion most
importantly few twists to the language.

My biggest (maybe nothing in the big picture) complain about Rust now is maybe
it's too community driven, which can sometime cause minor fragmentation.

As a personal developer, if I've already followed every best practice writing
my code, then to be honest, after the code is finished, I'm not willing to
rewrite my code just to make it dated or work again (I mean, I'll pay my time
to do it, but my hate meter will rise). Currently, Rust cannot fully deliver
that.

I think Rust need strong leaders to layout a clear and stable plan, so more
things can be standardized across it's ecosystem (Somewhat like what Go did,
for example, io.Reader && io.Writer is life changing for me). In that way I
can keep my hate meter at a safe level.

~~~
steveklabnik
Traits for interop are a prime consideration for std, even if we try to keep
it small. But we can only add things when they’re ready; that’s part of the
stability you desire.

Look at the Future trait, as an example. And rust has had the equivalent of
io.{Reader, Writer} since 1.0.

~~~
rqs
I know. But for me personally, the `io::Reader` and `io::Writer` is still not
comfortable enough. Mainly because it's return values, `io::Error` to be
specific. Because I found that in many of my cases, predefined `io::ErrorKind`
is not enough for me, this results my abuse of `io::ErrorKind::Other`.

In Go, `error` is an interface that can later be asserted, so I can return any
`error` then deal with them as late as I need.

This gives me ability to write some complex `io.Reader` and `io.Writer`. For
example, an `io.Reader` that can Decode data stream, and returns both
CodecError and IoError when it encountered any.

In Rust, if I want to write a similar thing, a HPACK decoder that returns both
`io::Error` and `HPACK::DecodeError` for example, I need come up with another
`Result` type that wraps both errors. This can sometime be tiring and makes
the code inflexible (As one simple change to the `Result` may effect the
entire call chain up and down).

BUT ... Maybe it's Go's fault, it treats me too well, make me want something
that I cannot have for free (performance cost) else where.

~~~
piano
> In Rust, if I want to write a similar thing, a HPACK decoder that returns
> both `io::Error` and `HPACK::DecodeError` for example, I need come up with
> another `Result` type that wraps both errors. This can sometime be tiring
> and makes the code inflexible (As one simple change to the `Result` may
> effect the entire call chain up and down).

Well there's stuff like error-chain to take care of the boilerplate...

Also, I believe you could define the equivalent of Go error in Rust as a trait
and box it (ie. a trait object). It could be used much the same way as in Go
with the additional benefit of Result being a sum type. I'm personally not a
big fan of this approach but I guess it might work...

~~~
rqs
> you could define the equivalent of Go error in Rust as a trait and box it
> (ie. a trait object).

I know this basically how Go's error handling works (Put error data on heap
and pass the reference), but I'm not fan of it (the put data on heap part of
it) too :(

I will try out the error-chain, thank you for reminding me that.

~~~
steveklabnik
The “failure” crate is an alternative to error-chain as well.

------
nevi-me
I've enjoyed learning Rust, but I'm at the stage where I'm hitting constant
stumbling blocks because of the slightly niche nature of what I'm doing.

It's the ugly side of Rust; when you're stuck with a series of problems that
you can't solve (or take too long to solve), when there aren't enough people
in the community to help you, and you end up being unproductive for a while.

Where I've seen small projects to their completion, Rust has been greatly
rewarding to me. It's the projects that are bigger and more ambitious where
I'm struggling.

> After reading the first 10 chapters of Programming Rust, I was able to push
> through the rest of the implementation. I still have open questions, and I’m
> not sure if the structure I used makes the most sense.

There's some chapters of TRPL and other resources that I've re-read a few
times by now. Learning the language ends up being quite a lot of an academic
exercise, but the benefit's that once a concept clicks, it paves way for many
other concepts.

My only advice to less experienced programmers (whom you're not) learning
Rust: Stay away from writing or rewriting time-critical applications in Rust
if you can't tolerate being stuck on a problem or series thereof for weeks.

~~~
manaskarekar
Usually someone will help you out on irc or on the rust subreddit, but I think
your point may still stand.

~~~
nevi-me
It depends, my biggest struggle right now is with the tokio/futures ecosystem,
so I'm on gitter::tokio quite a bit, and have posted once on /r/rust.

With patience, I eventually solve many problems, but the lead-time is costly.
Plus when I'm doing something wrong in my code, rustc could take over 5
minutes compiling, and then come back complaining. Even when I find someone
willing to help me debug, the process takes a few hours, and I end up feeling
bad for wasting someone's time.

~~~
nicoburns
I think the tokio/async ecosystem just isn't ready for prime time. Hopefully
this (and compile times!) get much better.

~~~
bluejekyll
The issue isn't exactly that it's not ready for prime time, but that it's not
ergonomic at the moment. The biggest issue that you have to get used to is
that pretty much everything has to be owned data, and no references passed
around when constructing Future types. This can feel like it comes into
conflict with the poll(&mut self) interface (in 0.1).

Also, I found truly understanding the fact that returning data from functions
either must be sized or boxed, no references. Again, the &mut self can come
into conflict here. But there are simple tricks for dealing with it, like
using inner enums for iterating through a state machine of the future, and
using Option where you can take() the value when ready.

You'll see these patterns if you look at the Future library and Tokio impls of
many of the core types. So I encourage you to generate docs with `cargo doc`
and then click the `src` link on any types you want to understand better. The
thing I wish I had internalized more earlier (and have been cleaning up a lot
lately), is that "Futures should do no work unless polled". This is easy to
mess up and regret later as you might accidentally start a Timer or initiate a
connection before polling the Future.

Anyway, hopefully people help out when you ask, though everyone's often busy
:)

~~~
nevi-me
One of the challenges I'm having now is with some library that connects to a
steaming pubsub server. I found a problem with the library, my use-case
differs from what's being tested, and because I'm struggling to use the
library the way the author suggests; I'm unable to convince them that being
unable to Clone their data structure is causing a problem.

I unfortunately am not at the point of "X didn't work, so I wrote Y" as that's
how we end up with competing libraries.

~~~
bluejekyll
Sometimes there are good reasons for not cloning, such as underlying resources
that can’t be cloned. But I agreed it can be ergonomically easier in many
cases. If they truly don’t want it, and you really don’t want to fork, can
rewrapping it in an Arc<T> or Arc<Mutex<T>> get you around the problem?

------
ammaskartik
I have been learning Rust on and off this year. I have been writing mostly GO
for the past few years, but am moving to coding almost primarily in Rust for
any new project, and porting over some older ones. Microservices, Data Layer,
etc... Honestly, while not perfect, its one of the most beautiful languages I
have ever come across. Plus, I have not enjoyed coding in a language this much
in a while.

~~~
dev_dull
How does your team (E.g., the people on the hook for
reviewing/supporting/contributing to your project) feel about the change?

This is a big difference when moving from Go. A language that nobody calls
beautiful, but is very easy for a team to contribute to and support (relative
to other languages).

~~~
cdoxsey
I don't think that's fair. I'm not entirely sure what beautiful means for a
programming language, but I've seen many examples of Go programs which
exhibited a beautiful simplicity. This project for example:
[https://github.com/inconshreveable/slt](https://github.com/inconshreveable/slt).

~~~
dev_dull
I didn’t mean to knock Go. It’s just that when I ask people what they love
about it, nobody usually expresses a “feeling” they have when they use it.

~~~
ammaskartik
Yes I agree. Beauty is highly subjective when it comes to programming
languages. Its definitely an expression of a feeling from use and relative
successes/failures.

I know people I highly respect that call C# with Linq & its lambda
implementation very beautiful, and I can see why, but I have not a strong
opinion one way or another on it.

I had a lot fun when initially learning Rust, and the way I have phased it in
to the projects (work & home) that I have been doing has led to successes,
which definitely increases my bias towards the fact rust is awesome =).

------
EduardoBautista
Rust is one of those languages that I just can't see myself ever working with
(I mostly do web dev), but it's a language I am really glad I learned and has
made me a better overall developer.

~~~
tech2
I kinda felt similarly until I found one of my existing web services wasn't
quite fast enough (currently serving around 1000req/s at peak). I could either
go for a third rewrite in yet another framework hoping to increase performance
by maybe 30%, or I could try something entirely new.

First attempt with rust more than doubled performance of the existing system
on the same hardware. Now I feel a need to learn more.

~~~
vmchale
What are you serving? Some of the Rust frameworks for backend should be able
to do more than 1000req/s, but it depends what you're doing.

~~~
tech2
The system's peak _usage_ is 60kreq/min (avg 1k/s), the Python code it's
written in can handle maybe 850/s per instance at 100% CPU.

Rust is fine, rust is managing almost 2k/s on the same hardware. And this is
when I know practically nothing about Rust, I expect I'm likely able to do
better given time.

It's acting as a simple filter and cache over JSON data on Postgres.

~~~
weberc2
I’m shocked that Rust only gave you a 2X improvement over Python (I’ve
rewritten a handful of Python services to Go and typically see 100-1000X
improvement). What is the bottleneck? Was scaling horizontally an option?

~~~
tech2
I suspect the reason it's not faster is one of the following:

    
    
      1. backend DB at its query limit
      2. this is basically my first rust program and I've done something stupid
      3. ab/wrk aren't scaling properly either (I know, not likely, but worth considering) when I'm testing it
      4. bandwidth/IO limits on the AWS instance types I'm running this on
    

There are other possibilities too I guess. I was mostly doing this as a means
to learn Rust though, I'd only go live with it once I had decent tests and
everything else.

~~~
the_duke
What web framework are you using?

Are you using a database? If so, which one? Are you using a cache like Redis?

I agree that a 2x speedup is a terribly low for a Python to Rust rewrite and
shows that Python is unlikely to be the relevant bottleneck here.

~~~
weberc2
> What web framework are you using?

I can't imagine the web framework is the bottleneck...

~~~
the_duke
It might be because if it's a tokio-core based one OP might be blocking the
event loop too much.

------
joobus
I'm optimistic for the future of Rust. I currently program in Go for server
side web stuff, but with the proposed changes to the Go language, the decision
to choose Go over Rust becomes less compelling; Rust already has generics, a
competent module system, better error handling, and ADTs. Go had a very narrow
scope and very clear oversights, which are now bigger issues they are trying
to shoehorn solutions into with the go v2 proposal.

I've been following rust for a while and have known it is not web ready, but
early next year I think will be a different story.

~~~
Dowwie
It's web ready. It's very web ready.

~~~
jayflux
Woah, I’m a big fan of rust, but saying it’s web ready is disingenuous. Rocket
isn’t stable, most of the libraries rocket depends on aren’t stable either.
Making http requests.. are there any stable http libraries yet? Last I checked
Hyper was still on a 0 release with no h2 support.

Rust has conquered a lot, but it’s web service/API story is not complete yet.
Go is ahead in this respect.

~~~
Dowwie
Check out actix-web: [https://actix.rs](https://actix.rs)

Does my proclamation still seem disingenuous to you? If so, why?

------
erwan
I love Rust, but in all honesty I wouldn't use it vs. Golang or C++17 for
something that isn't a critical system (e.g a cryptography lib) and even then
I'm not sure I wouldn't use something like OCaml instead.

The curve to productivity seem way too steep for the payoff.

~~~
ilovecaching
Woah, woah, woah. First, Go and C++ are _vastly_ different languages. Apples
and oranges.

C++ is _huge_. It takes an incredible amount of effort to become a proficient
C++ developer, and even then, C++ offers none of the amazing safety guarantees
that Rust's borrow checker enforces. It's old language with sedimentary
layers, including C backwards compatibility. Rust is no where near as complex,
and Rust does 5x more to ensure you use Rust correctly. It has brought so many
crucial advancements as well: immutable by default, typeclasses instead of OOP
(thank god), real sum types, better unicode support, better concurrency
primitives, and _much much much_ better tooling and package management. No one
in their right mind would be cracking out another C++ project if they took the
time to learn Rust and C++.

Go isn't really in the same league as Rust, C++, or C. It's syntax is
deceptively C like, and it has an equally poor type system, but it's
performance is closer to Java, which is a few orders of magnitude slower than
C++. Despite pushing outdated concepts like null and raw pointers on to the
programmer, it has a runtime with a stop the world GC with no guarantees about
object placement on the stack or heap. Go is also incredibly divisive, it's a
step backwards that hardcodes a few useful container types, and gives you no
facility to create your own. It has a hard coded method of concurrency
(goroutines). While useful in it's simplicity, it lacks the generality one
would expect of an industrial language, and these concerns are only now being
accepted by the Go team in their 2.0 drafts. Many people believe that Go rose
to popularity because of the authors and the company sponsoring it, not on its
technical merits ,and Brad Fitzpatrick, one of the maintainers, even said the
language brought nothing new to the table aside from better concurrency
support in the Gotime podcast episode he attended.

~~~
xyzzy_plugh
> Many people believe that Go rose to popularity because of the authors and
> the company sponsoring it, not on its technical merits

I don't believe this to be the popular opinion. Originally Google's
involvement dissuaded me, and indeed the very Googly bits have been the worst
(context.Context), but the rest of it is markedly un-google-like. It's much
more of a Bell Labs feel, with a focus on tool efficiency and stability.

> Brad Fitzpatrick, one of the maintainers, even said the language brought
> nothing new to the table aside from better concurrency support in the Gotime
> podcast episode he attended.

I think that was very much the intent. There were a lot of good ideas over the
years (especially in Plan 9) and Go is really just a modern, polished revision
of those ideas glued together.

Go is a _systems_ language at heart. It focuses on maintainability and
literacy, and that's where it leads the pack in my eyes. It's possible to
squeeze pretty phenomenal performance out of such a simple language. It's easy
to drop into assembly for ultimate optimizations.

Perhaps generality is a mistake? I don't miss it. I've never found joy in
debugging someone else's generalized metaprogramming.

Building software at serious scale has led me to appreciate the wisdom buried
within Go. It's boring and I love it.

I've written a bit of Rust (and a lot of C++) which I find enjoyable enough,
but they're tools I rarely find myself reaching for.

~~~
ilovecaching
> There were a lot of good ideas over the years (especially in Plan 9) and Go
> is really just a modern, polished revision of those ideas glued together.

Plan 9 is an operating system. If you're referring to goroutines, CSP is
completely unrelated to any of the work done at Bell Labs. That was Hoare. Go
also kept a ton of terrible ideas, like nil, void (interface{}), and default
mutability.

> Go is a _systems_ language at heart.

It really bothers me when people say this, because it's just untrue
regurgitation from the Go team. It's not a systems language. It's a language
that's pretty good for small web services. It has expensive interop (Solomon
Hykes commented on this during one of his Gotime interviews) with C (even the
Go team says cgo is not Go).

> It's easy to drop into assembly for ultimate optimizations.

You can only drop down into Plan 9 assembler, which is essentially useless.
Write me an SGX lib without cgo in x86 and you can make that claim.

~~~
pjmlp
People are doing OS research in Go, and Fuchsia core components like the
TCP/IP stack are written in it, regardless of what the HN crowd thinks where
Go should be used.

[https://github.com/mit-pdos/biscuit](https://github.com/mit-pdos/biscuit)

[https://github.com/ycoroneos/G.E.R.T](https://github.com/ycoroneos/G.E.R.T)

Last version of Plan 9 was actually Inferno, which HNers keep forgetting
about, which used Limbo for userspace code.

Limbo uses the channel syntax later adopted by Go.

~~~
UK-Al05
People do os research in c#

~~~
pjmlp
And hopefully in the future even more so.

I was quite disappointed how WinDev managed to sink Longhorn and later WP 7.

------
js2
I think folks might find Sentry’s use of Rust interesting. Sentry is quite
invested in Python on their backend, but needed additional performance mostly
related to symbolication of crash reports. So they have a Rust symbolication
library with Python bindings giving them the best of both worlds for their
app.

[https://github.com/getsentry/symbolic](https://github.com/getsentry/symbolic)

------
tsomctl
Can anyone recommend exercises for learning a new language. For example,
something like "implement a class with these methods", or implement a function
that does this. Something that is realistic, should only take an hour or two
to implement for a competent programmer, requires you to learn more
complicated features of a language, yet I can finish before getting bored or
frustrated?

~~~
tomjakubowski
I'd also like to hear what others do to learn languages. I like to write a
little RPN calculator. The program's interface might vary depending on the
language: to learn browser JS, you might do a DOM-based UI; for Rust it might
be a CLI; for Go or Erlang maybe a line-oriented network service.

Depending on the interface, this tends to exercise language and runtime
features like: string handling and parsing, event handling, conditionals /
pattern matching, etc. "Calculator" is also a big enough problem space that
you can come back to it to try out more interesting language features (e.g.
using Rust enums to model your calculator's operations).

~~~
djhworld
I usually write data structures like Linked Lists when learning a new
programming language.

This was a critical mistake for me when learning Rust and led to many, many
stumbling blocks

------
asdfman123
Question: does "getting rusty" mean you're getting better or worse at Rust?

~~~
Axsuul
Worse. I think "getting oxidized" would mean getting better.

------
qaq
Learning Rust at the moment and Pony looks really interesting too. I think at
this point in time it's safe to say Rust is here to stay so the investment of
time into learning it is well worth it as it will stay around for a long time.

------
13415
I've learned a bit of Rust recently but then started programming in Go. Now
that I've learned a decent amount of Go I'm thinking of giving Rust another
try, because Go has so many obvious weaknesses.

However, I'm still torn between those languages, which I both consider as
fancy alternatives to C++ with a growing amount of libraries and community
support. I neither like Go nor Rust, but learn them to keep up to date and
because I need something with good tooling and many libraries that creates
compact and fast executables. Rust still seems overly complicated to me,
though, and I say that as someone who enjoys programming in Ada.

~~~
whytaka
Could you elaborate a bit on the obvious weaknesses in Go?

~~~
13415
Arbitrary examples off the top of my head:

lack of references, no generics, verbose error handling, a few quirks (e.g.
need to write (*slice)[i]), inconsistencies like new vs. make, interface{}
hacks where there could be a zero-cost abstraction, oddities with untyped
literals, no way to declare "not null" pointers and the Million Dollar
Mistake, built-in functions for built-in primitives (i.e., append(slice,
datum) instead of slice.append(datum))

Stuff like that, which has been discussed over and over. Go is a bit of an odd
language if you're used to languages like Ada, CommonLisp, or Racket, but I
really like it a lot. I like the sense of pragmatism, that it has been
developed to get things done.

I believe that Go2 will be even better and am especially happy that the Go
team has decided to adjust and include generics rather than stubbornly
insisting that they are not needed.

~~~
whytaka
Thank you!

------
vmchale
I don't actually think Rust has that many stumbling blocks compared to other
programming languages. It's a pain in the ass compared to Haskell but not e.g.
Java.

------
kieckerjan
Rust's main attraction for me (coming from a C background) is that it allows
you to do threading reasonably confident that you will not enter a world of
pain after a simple mistake. In an ever more concurrent world that is a major
plus.

------
snrji
I enjoy coding in Rust, and I think it's a step in the right direction, but
I'm still looking for a general purpose programming language which model
IO/State effects the same way languages supporting functional programming do
with pure functions. Haskell monads are not granular enough. The closer thing
I've seen is Purescript, but still is not general purpose enough. Solidity's
"pure" annotations are a step in the right direction, but I'm speaking about
something much expressive. Also, it should have a Rust/C-like syntax in order
to be able to be mainstream, but I'm happy with Haskell-like syntaxes.

~~~
how_to_bake
Check out Nim. They recently added support for a function declaration in
addition to a proc. Function automatically checks that it is a pure function
with no side effects.

Considering the flexibility of the language as a whole, this is really cool!

------
atoav
I didn’t really find Rust especially hard to learn. I came from Python with a
very beginner level experience in embedded C.

The hardest part is probably to stop yourself from trying to applying
solutions you learned in other languages into Rust. I caught myself multiple
times trying to put things into python style classes, which failed horrible
each time. The moment you grasp how to do things the rust way you will end up
with solutions that are most likely more elegant, safe and fast than the thing
that you tried to do first.

Over time (a few weeks) I managed to get a good enough intuition on Rusts
concepts of ownership to not having to constantly think about it.

------
ram_rar
Rust has definitely made me a better systems engineer overall. But, its not a
language I can use for web dev. I hope, it gets easier to integrate rust into
python in future.

~~~
chimpburger
[https://rocket.rs/](https://rocket.rs/)

~~~
juststeve
nah actix web and diesel

------
sidcool
How does it compare to Go? Concurrency and safety seem to be the forte of Go
lang too.

------
misrab
Try writing a linked list in Rust...or implementing a graph. It's not
intuitive I think?

------
throwaway487548
It seems that the main problem with Rust is that it has been grown up _not_
from the CS and PL theory _fundamentals_ , like ML, or Scheme or Erlang or
even Go, and it is obviously not a small, clean language everyone loves and
appreciates as being beautiful. In other words it is just little better than
C++, which is a crap.

If a language could be grown from ML (Ocaml) roots (like Scala) instead of
C++, it could be _much_ smaller, cleaner and more pleasant to work with.
Rust's only innovation is in the compiler tech, which could be ported and
_simplified_ (due to more predictable semantics of a functional language) to
any ML-family language.

I cannot overemphasize how beautiful the pattern-matching with local bindings
on algebraic data-types is, and what a wonderful thing is Erlang's pattern-
matching on receive, and how, say, protobuf is basically product/record-types
annotations, which could be done in a ML-family language itself etc.

Rust is under the curse of C++ (a statically typed and standardized dialect of
PHP3) if you wish. It is obviously good language compared to C++, but somehow
Ruby-ish, compared to ML-family languages.

It is actually a pity that Rust and not ML/Ocaml are considered cool and sexy
by modern teenagers (like it used to be with Ruby and with Rails not so long
ago). ML is much better starting point than C++. Perhaps, polished to
perfection languages (Scheme, Haskell) are less appealing for the crowd being
too dry, without ambivalence.

BTW, the next cool language definitely should be something like typed Erlang
with Ocaml's syntax ;) - a hybrid into which typed Python or Typescript are
growing into.

~~~
UK-Al05
Rust is ML like. It can do pattern matching and has adt type system. It uses
expressions rather statements

If you remove gc from ocaml, and added in compensating alternatives it would
end up looking something like rust.

I think a lot of the adversting around rust in a "better c++" but its actually
ocaml like but not mentioned to avoid scaring away traditional systems devs.

~~~
throwaway487548
Rust did a lot of things nice, but it is over cluttered with all these
particularities everywhere, which could be hidden by better default
conventions.

For example, everything should be a reference by default, and use of explicit
& is stylistically bad.

Or why in let mut iter = a.iter(); iter is mut? It should be a simple closure
which follows a protocol. In what sense it is mutable?

And such small warts are literally everywhere, together resulting in a
clutter.

A functional language uniform defaults (everything is an expression,
everything is a binding which implies everything s reference) are much better.

~~~
steveklabnik
Iterators contain internal state that gets mutated as you iterate. So it needs
to be mutable.

~~~
throwaway487548
But the whole idea is that once a closure implements an interface its internal
state is strongly isolated behind the abstraction barrier of the interface and
no one knows or cares whatever state it has, if any. It is very CS 101.

~~~
steveklabnik
Well, first of all, it's not a closure, it's a struct, though closures are
syntax sugar for structs.

Second, what you said is true, but also not really relevant; mutability is
part of the API in Rust, and so that _is_ part of the interface.

To make it more concrete, [https://doc.rust-
lang.org/stable/std/iter/trait.Iterator.htm...](https://doc.rust-
lang.org/stable/std/iter/trait.Iterator.html#tymethod.next), the protocol,
takes &mut self. So it must be mutable. It's _following_ the principle you're
talking about.

