
Rust for Python Programmers - zsiciarz
http://lucumr.pocoo.org/2015/5/27/rust-for-pythonistas/
======
asQuirreL
Nice writeup! One thing though, I believe Rust's BTreeMap [1] is a B-Tree (not
a binary tree, as suggested), i.e. it's a tree whose branch factor is
generally greater than 2.

The docs say that if you don't give a branch factor, a sensible choice is made
for you, probably to get nodes to fit neatly into cache lines, so seeing as we
are storing 35 unsigned 64 bit integers, this would be around 16 or 32
elements in a single node, and a depth of about 2. This means that, because
the current implementation of BTreeMap does linear searches at insertion, for
this _particular_ use case, the BTreeMap isn't doing much better than a plain
old array, that you are insertion sorting.

TL;DR: Storing the results in a vector and then in-placing sorting it could be
faster, but not noticeably. I know this isn't the point of the article, but it
was just an observation I had :)

[1]: [https://doc.rust-
lang.org/std/collections/struct.BTreeMap.ht...](https://doc.rust-
lang.org/std/collections/struct.BTreeMap.html)

~~~
dbaupp
_> sensible choice is made for you_

At the moment, it's chosen to be 6: [https://doc.rust-
lang.org/src/collections/btree/map.rs.html#...](https://doc.rust-
lang.org/src/collections/btree/map.rs.html#156) (note the FIXME though).

------
swah
Armin's Flask was probably best experience I've ever had with a piece of
software. Clean, modular, pragmatic and very well documented. I only stopped
using because "websockets, Go, SPA", though I never really finished a side
project with those yet.

I can't think of a single WTF moment I had with it. Several "OMG this guy
thought about this too" moments.

~~~
simi_
Since I'm in the same boat as you, what about Falcon? Are the extra
performance and customisability worth switching?

[http://falconframework.org/](http://falconframework.org/)

edit: Thank you for your reply - by the way yes, I am indeed only building a
REST API.

~~~
EpicDavi
I used Falcon for a relatively large project and enjoyed using it. It is
noticeably faster than Flask and I can write code faster as well. It is very
much still growing and features are being added. They call Flask "Batteries
not included" but Falcon takes that to another level. There are also not very
many extensions in comparison to Flask. If you are writing an API exclusively,
I would choose Falcon. However, if you have any HTML/CSS/JS, Falcon is
probably not suited for the project.

EDIT: Both are very good.

------
progman
I honestly respect the power and rapid development of Rust but I think that
Nim ([http://nim-lang.org](http://nim-lang.org)) is a much better alternative
to Python than Rust, as its syntax and "feeling" is much closer to Python, and
also the productivity level. In Nim I get things done much faster than in
Rust. Nim is easy to learn but Rust requires a certain amount of knowledge and
experience for good productivity.

I consider Nim the "better Python", and Rust the "better C++".

~~~
amyjess
Expanding on that, I'd say that Nim is a "better" [1] Python [2], Rust is a
better C, and D is a better C++.

[1] For some purposes. As a long-time Pythonista, I've looked at Nim, and I
have no desire to replace Python with Nim in my daily use. But my uses for
Python aren't the same as everyone else's, and Nim looks like it could be a
fun language to play around with and learn, at least.

[2] Even more accurate, Nim is a better Object Pascal.

~~~
masklinn
Rust is a better C++ more than a better C, it has similar goals to C++ of
advanced zero-cost (at runtime) abstractions, not so much of being a portable
assembly. Like C++ it can be an alternative to C in some contexts.

D intended to be a better C++, but that hasn't panned out well in practice for
various reasons (one of them being the use of a GC and much of the standard
library depending on it, though IIRC they're trying to fix that).

------
aidos
That was a really interesting introduction. I hadn't looked at Rust before and
that gave me a good feel for it. Thanks for putting it together, Armin.

A minor peeve of mine is examples between languages that differ in ways that
are unimportant (though maybe it can just justified as "idiomatic code"). It
adds bias to the demonstration.

We could have written the python one like the following to wrap the lock up
with the results structure (and get the automatic sorting behaviour, too):

    
    
        import queue
        from threading import Thread
        
        def fib(num):
            return 1 if num < 2 else fib(num - 2) + fib(num - 1)
        
        def thread_prog(results, i):
            rv = fib(i)
            results.put((i, rv))
        
        def main():
            results = queue.PriorityQueue()
            threads = [Thread(target=thread_prog, args=(results, i)) for i in range(35)]
            [t.start() for t in threads]
            [t.join() for t in threads]
            while not results.empty():
                i, rv = results.get()
                print("fib({}) = {}".format(i, rv))
    

Though, I've also taken other liberties to make it shorter. I normally stay
away from threading in python because the GIL makes it a bit of a waste of
time in most cases, and who needs the complexity in their lives?

Again, thanks for the overview, I enjoyed it.

~~~
scott_s
Consider that such examples are often not about _convincing_ , but _teaching_.
That is, they often not trying to convince the reader, "Language X is better
than language Y." Rather, the intent is more, "You already know language X, so
here's some code in X. Now here's how you would do the same thing in Y." It's
a pedagogical tool, rather than an argument tactic.

~~~
Dewie3
According to some people all mentions of PLs have to be evangelical and
confrontational. :-)

------
barosl
> In Python a function can fail with any error and there is nothing you can do
> about that.

To be fair, the adorable `except:` black magic exists there to be used in such
a case. Of course its use is extremely dangerous for obvious reasons (it even
catches the `SystemExit` exception!), so I can understand why the author
didn't mention this.

> This is a big change in how you think about programs but you will get used
> to it.

Possibly! But I have a feeling that the ownership model would be the biggest
blocker to newcomers, as well as the largest innovation Rust brought to the
mainstream languages. I can already hear the crowd saying Rust's just a giant
mess, after struggling with the borrow checker. This may impact the success of
the language. Now that Rust is post-1.0, we will see.

> the constant encoding and decoding you have to deal with in Python just to
> support O(1) string indexing.

Strictly speaking, Python also doesn't support a complete character indexing,
because it works on code point basis. O(1) string indexing is largely a
myth.[1] But I'm sure that the author definitely knows about this, considering
his previous rants on Python's Unicode handling. ;)

Regarding Unicode handling, I think Swift's `String` type is arguably more
complete than Rust or Python. Its internal representation is UTF-16, possibly
due to the interoperability concerns with `NSString`, so it can't compete with
Rust on the performance aspect. However, it indexes a string by grapheme
cluster (so Swift's `Character` type is actually a slice, not an integer) and
compares the characters by their normalized forms, which eliminates many
mistakes that can be made by careless programmers, including me. Of course the
same thing can be done in other languages using external libraries, but the
official support residing in the built-in string type is very nice to have.

[1] [https://hamstergene.github.io/post/wchar-is-
useless/](https://hamstergene.github.io/post/wchar-is-useless/)

~~~
Grue3
>To be fair, the adorable `except:` black magic exists there to be used in
such a case. Of course its use is extremely dangerous for obvious reasons (it
even catches the `SystemExit` exception!), so I can understand why the author
didn't mention this.

This is why you use "except Exception:" which doesn't catch system exceptions.

~~~
wyldfire
"except Exception:" is rarely what you want IMO. It also catches SyntaxError,
which is almost always a design error -- one you'd typically prefer would halt
the system.

Unfortunately there's no common parent to
EnvironmentError/SystemError/RuntimeError/etc that excludes SyntaxError.

~~~
mixmastamyk
I can't seem to repro that, SyntaxError seems to happen before the code runs
the first time. (2.7 Ubuntu)

~~~
wyldfire
SyntaxError can happen as a consequence of loading a module (hitting an import
statement, etc). But for a simpler example, replace SyntaxError with NameError
and it's still almost always a design error that you probably have no sane way
to handle in an exception handler (other than to mask the problem).

Python's a very dynamic language and so of course you could come up with
examples to the contrary (ones where the user input could trigger SyntaxError
or NameError).

~~~
techdragon
But the only universally good reason I know of where you should be wrapping
imports in try except is 2/3 compatibility or other module/library import
fallback. For these you need to be catching syntaxerror and other system
errors.

------
bitL
A quick question from a Rust noob: if I knew Python, why should I try Rust?
What is in there that would make my life better? At first glance I see a lot
of unimportant syntactic sugar or concepts I am not sure would make my life
any easier (ownership tracking vs garbage collection).

~~~
untothebreach
As a current python & rust user, I can say that I picked up rust because I
liked the idea of a systems language that could give me c-like performance,
without having to use C. Rust seems, to me, like a combination of the best
parts of python (traits as pseudo-duck-typing), haskell (type inference,
functional concepts), and C(++) (speed, no GC).

As @mitsuhiko says in the article, it is very easy to export symbols from a
Rust library so that they can be used via CFFI, so the possibility of
"dropping down to Rust" instead of "dropping down to C" is very attractive to
me.

~~~
Cyph0n
I have my eyes on Rust, mainly for no GC and its ownership system, and Nim for
its clean, Python-like syntax but with C performance.

I also have Julia in my mind for my next scientific computing (image
processing, DSP) project.

~~~
untothebreach
I keep on messing around with Julia, but I never stick with it. I have nothing
in particular against the language, but I don't do a lot of scientific
computing, so my motivations to use it are not that great.

~~~
Lofkin
Why can't it be used for general computing?

~~~
Fede_V
It can. However, Julia made a very strong push to target the scientific
computing niche (very strong array support, ease of writing tight loops in
native code, etc) - and such it has a very quickly growing ecosystem of high
quality scientific packages.

In comparison, Julia has relatively few web frameworks, GUI toolkits, etc..

------
sinistersnare
A great writeup! A lot of the Rust community seems to have come from the Ruby
side of things (with writings such as "Rust for Rubyists" by Steve Klabnik),
although I feel that Rust and Python share many ideas that Ruby does not
concern itself with.

I particularly like the section about string handling. There is a reason that
Rust strings are hard, and I will make sure to point to that section whenever
mentioned.

~~~
porker
> A lot of the Rust community seems to have come from the Ruby side of things

People say that about Elixir too. No doubt about other languages as well.

I think the truism is: "(ex-)Ruby users are more vocal about what they use"

It'd be fascinating to do a study on personality types/traits and programming
language use.

~~~
sinistersnare
Yeah, the Ruby community is very blog-centric, and I have thought of that
before, so you are most probably right.

I too would like to see a study, but I would have no idea how to conduct it!

Maybe the Ruby community is just reaching out everywhere trying to find a
better language (just a jab from a python dev ;P )

------
caioariede
Between Rust and Go (for Pythonistas) I still prefer Rust.

One thing that bothers me in Go is that, like Ruby, when you import something
you don't know exactly what's being injected in the context. So it's quite bad
to understand from where some things came from. I like more the Python / Rust
approach for that.

~~~
ForHackernews
Maybe it's just because Go has Google backing it, but I seem to hear way more
about Go than I do about Rust. I have my doubts about whether Rust will have a
viable ecosystem in 4-5 years. It's a shame because Rust seems like a more
interesting language to me.

~~~
kibwen
Rust is currently backed by Mozilla, Samsung, and an expanding coalition of
startups. There are other large companies experimenting with Rust at the
moment, but I'd rather wait for them to come out with their own announcements.
The community is hugely active and growing at an increasing rate. There are
four Rust books in the publishing pipeline and Rust's first conference will be
held this year, with at least two conferences already planning for next year.
I wouldn't worry about the state of Rust's ecosystem in five years. :)

~~~
alfiedotwtf
Rust conferences? I've seemed to have missed this. Any links/info?

~~~
steveklabnik
We announced [http://rustcamp.com/](http://rustcamp.com/) today.

~~~
alfiedotwtf
Ah cool. I thought that might have been one of them. Was just interested if
others have been announced too :)

------
antman
I only do data analysis but cython [0] is pretty much the fastest way for me
to produce fast code. I tried to do some things in Rust but my productivity
fell, and I could not figure out how to fix some error messages. [0]
[https://honnibal.wordpress.com/2014/10/21/writing-c-in-
cytho...](https://honnibal.wordpress.com/2014/10/21/writing-c-in-cython/)

~~~
synparb
Here is a simple example I just threw together of calling a Rust function from
within Cython: [https://github.com/synapticarbors/rust-cython-
test](https://github.com/synapticarbors/rust-cython-test)

I use cython extensively in my work and it's super productive for me as well,
but I could see maybe toying with Rust more in the future for some really
specialized things.

------
Ygg2
Does anyone know what author meant to say?

    
    
            3) have a very similar Unicode model which is to map
         Unicode data against arrays of characters where a 
         character[sic]. In Rust however...
    

It seems a part is missing.

Don't get me wrong, not criticizing author here, happened to me lots of times.

~~~
xiaq
It makes sense if you remove "where a character"... Or change it to "where a
character is a Unicode codepoint".

This is basically saying Python uses a fixed-length encoding (UTF-32) where
each codepoint takes constant storage, as opposed to UTF-8 where the storage
of a character depends on where it is in the Unicode plane. A useful analog,
if you know C, is that Python always uses wchar_t[] where each element is a
character, while rust uses char[] and then the elements are not characters but
UTF-8 bytes.

There are obvious up- and downsides to both approaches.

EDIT: As suggested by two children, with Python 3.3+, the fixed-length
encoding Python uses depends on the highest codepoint in the string and is
often not UTF-32. With earlier versions there are "narrow" and "wide" builds
which use UTF-16 and UTF-32 respectively.

~~~
ubernostrum
On Python 2.2 through 3.2, CPython could be compiled with "narrow" or "wide"
Unicode strings. On a "narrow" build, Unicode strings internally were
represented using two-byte characters and surrogate pairs. On a "wide" build,
Unicode strings were represented internally using four-byte characters.

On Python 3.3+, the distinction is gone, and Python uses either latin-1, UCS-2
or UCS-4 depending on the highest codepoint in the string (i.e., a string
containing only codepoints in latin-1 will be stored internally as latin-1; a
string containing at least one codepoint outside the BMP will be stored
internally as UCS-4, etc.).

~~~
masklinn
It's still fixed-length codepoint encoding, even if the specific encoding
depends on content.

------
castell
We have several similar headlines on HN lately.

Go/Rust/Erlang/Elixir/Node/Nim/Julia for Python programmers

Is there a trend away from Python2/3 or Ruby to language X?

~~~
tormeh
I think it's more that many language designers and/or fans don't really
understand why Python is so popular, and therefore think the Python ecosystem
is an easy ecosystem to draw developers from.

~~~
Dewie3
I haven't had the impression that language geeks[1] complain a lot about
Python. They certainly complain more about other dynamic languages.

[1] I don't know if I've seen enough _designers_ ' opinions about it to say
anything.

------
JshWright
For the mutex example, the explanation says:

"So here is how the code works: we count to 20 like in Python"

That's a typo, right? Both examples count to 35, not 20 (I'm not crazy,
right...?)

------
whonut
As someone with experience only in Python, is Rust a decent place for me to
learn lower-level concepts or should I go with C/C++?

~~~
steveklabnik
This is a very common question, and there's two camps:

1\. Learn C, then learn some C++. You won't appreciate Rust until you've felt
the pain that it solves.

2\. Learn Rust. Why bother going through all that trouble on your own when you
can have the compiler help guide you.

and a third position:

3\. Rust is still new enough that you'll find way more information with C, so
you should just learn that even if Rust is better in a vacuum. Learning is
easier with copious help and tutorials.

I personally fall in camp 2, and sometimes 3.

~~~
barosl
This is a nice summary! FWIW I'm more likely 1, as I've seen many people
coming from dynamic languages being frustrated about the "Rust way". Not only
the ownership model, but also compiling, optimization, etc.

3 is certainly a problem, but personally I found enough materials to learn
Rust even for now. However more "friendly" resources would be definitely
welcome.

~~~
e12e
While I'm new to rust, and have just been dabbling in C -- as another comment
mentions here: you really have to deal with the borrowing in C as well (and
the compiling/optimization). If you _don 't_ deal with in C (without any real
language support) -- you'll get bugs. If you're very lucky, and made a great
effort in turning on warnings[1] -- you'll be aware of those bugs. Most likely
you won't.

[1] See eg: [https://github.com/incrediblesound/Graph-
Reply/commit/929e57...](https://github.com/incrediblesound/Graph-
Reply/commit/929e5733caf02ff1873e59add4b4834555dcfbfa) for a little bit about
C and warnings.

------
krick
By the way, about Rust error handling. I like the concept that any error is
being returned as a function result, but there's is a huge practical problem I
don't understand how to solve with this approach. Exceptions (kind of) solve
it automatically.

What if the information that "computation failed" is not enough? Say, I wrote
a `getItem(User) -> itemId` function, which does a lot of calls and can fail
for multiple reasons. Later I will have to admit that my API is not perfect:
user isn't quite ok with the fact that operation failed, he wants to know
_why_ it failed: maybe there's no items to get at the time, maybe he isn't
permitted to get them, maybe that permission is computed in real-time based on
how many clicks he made today or anything else. What do I do now?

If getItem was throwing exceptions, I can fix it right away. It's not my
favorite solution of that problem, but it works: I catch all exceptions
separately at the caller and do something. I can provide user-friendly message
as the text, that the exception will carry.

But if I was using something like Maybe monad for the error mechanism, I'm
pretty much fucked. Now I have to go through huge getItem function and
refactor it using some custom container-type as a return value, which will
carry the reason the call failed, as well as the data itself.

From what I understood, Rust's error handling is exactly such Maybe monad with
a different name. Is there built-in, idiomatic way to solve that problem?

~~~
dbaupp
The `Option` type (what Rust calls Maybe) is rarely used for error handling.
As the article describes, Result is normally used, which allows attaching
arbitrary data to the error case: [http://doc.rust-
lang.org/std/result/](http://doc.rust-lang.org/std/result/)

For example, the io library generally returns [http://doc.rust-
lang.org/std/io/struct.Error.html](http://doc.rust-
lang.org/std/io/struct.Error.html) as the information when errors occur, which
includes all sorts of possibilities for what went wrong: [http://doc.rust-
lang.org/std/io/enum.ErrorKind.html](http://doc.rust-
lang.org/std/io/enum.ErrorKind.html)

~~~
e12e
In addition to what dbaupp mentions, you might want to look at:

[http://blog.burntsushi.net/rust-error-
handling/](http://blog.burntsushi.net/rust-error-handling/)

(which was posted to hn a while back)

------
SimionBaws
Can you write python modules in rust?

I would like to write small parts of my project as separate high performance
modules, and I don't want to do it in C, it makes me sad.

~~~
gthank
TL;DR Write it in Rust, export via FFI, bind from Python via cffi.

The long version is: go watch this video from PyCon that will answer this
question and probably others
[https://www.youtube.com/watch?v=3CwJ0MH-4MA](https://www.youtube.com/watch?v=3CwJ0MH-4MA)

~~~
steveklabnik
That video and a similar talk I've given at Ruby conferences inspired me to
make a chapter for the book: [http://doc.rust-lang.org/stable/book/rust-
inside-other-langu...](http://doc.rust-lang.org/stable/book/rust-inside-other-
languages.html)

------
omouse
I like the way the error handling works; it's a pattern I try and use in
Python by creating custom exceptions that basically pass up whatever specific
exception is caught.

------
upofadown
The more popular version of Python (2) does not enforce conversion of Unicode
to UCS-32. The criticisms in the article mostly apply to Python3.

~~~
gthank
Python 2 will store Unicode as either UCS-16 or UCS-32, depending on how it
was compiled. The horrible monstrosity that is the default "string" (those are
scare quotes; I know how the formatting on here works) in Python 2 is not
Unicode, so it obviously doesn't use UCS-16 or UCS-32.

~~~
cygx
UCS-4 is UTF-32 (or, to be pedantic, a superset), whereas UCS-2 is the fixed-
width predecessor of UTF-16.

There's no such thing as UCS-16 or UCS-32.

------
swah
Do Rust newbies also complain about the lack of exceptions like in Goland
(myself included even understanding their reasons..) ?

~~~
pjmlp
No because Rust offers a more natural way to deal with them, instead of ifs
everywhere.

Also known as railway programming in FP circles.

~~~
platz
> railway programming in F# circles

FTFY

~~~
unmole
Pretty sure pjmlp meant Functional Programming.

~~~
platz
"Railway Oriented Programming" is a term coined by Scott Wlaschin, a prominent
F# practitioner who popularized the term with helpful blog posts, slides, and
speaking events.

Outside of the F# community (i.e. those that have not seen Wlaschin's
materials) however, the term is rarely used. The larger FP community has more
more general terms they use instead for the whole class of patterns
surrounding this.

~~~
pjmlp
You are correct. I just thought the term was more widely known outside the F#
world.

~~~
platz
well it could be, I certainly don't speak for everyone; just haven't seen it
personally myself yet.

------
mrfusion
Is that site down for anyone else?

------
Profpatsch
Dude, give the code some space. It can’t breathe cramped like this.

