14 ms·
Rust for Python Programmers
- sinistersnare 11y agoA 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.
- bad_user 11y agoWhat ideas are you talking about?
- sinistersnare 11y agoThroughout my experiences with both Python and Rust, I am able to use the same ideas to accomplish tasks. The Zen of Python fits both languages in my opinion also. I think that they are both very pragmatic languages, they are not trying to be expressive in the way that Ruby does, or try to write the coolest one liner, writing Rust or Python is about writing good code. At least in my opinion. I think both languages complement each other extremely well, and I hope to see more of the two of them meshing in the future. Im not sure if I actually said anything here... sorry im tired. What I meant to say is that I feel that idiomatic Python can look a lot like idiomatic Rust, and that they can complement each other in code by using Rust instead of C.
- porker 11y ago> 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 11y agoYeah, 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 )
- deleted 11y ago[deleted]
- asQuirreL 11y agoNice 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.html https://doc.rust-lang.org/std/collections/struct.BTreeMap.ht...
- dbaupp 11y ago> 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#156 https://doc.rust-lang.org/src/collections/btree/map.rs.html#... (note the FIXME though).
- the_mitsuhiko 11y agoFixed. I primarily picked the btree because it made the example nice and short :)
- Ygg2 11y agoDoes 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 11y agoIt 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.
- lucian1900 11y agoPython (at least 3) actually uses the narrowest encoding that can fit the string, so it'll rarely actually use UTF-32.
- xiaq 11y agoThanks, that is good to know.
- ubernostrum 11y agoOn 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.).
- barosl 11y ago> 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/
- masklinn 11y ago> 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!) And KeyboardException. Which is why it's very strongly recommended to never write bare excepts in Python (unless you're going to rethrow immediately and just want to cleanup or log on exception), and always `except Exception` at least. > Regarding Unicode handling, I think Swift's `String` type is arguably more complete than Rust or Python. Very likely considering it inherits Apple's concern for internationalisation, Objective-C was one of the very few languages which exposed relatively easy grapheme cluster level manipulations. I believe Rust's string mostly tries to provide a sensible interface, not a complete one, which is why you can iterate on bytes and codepoints (decoded on the fly) but more complex unicode operations tend to be left to external libraries. Whether that's a good idea is debatable, on the one hand implementing fully unicode aware strings would make that part of the standard library much more complex and bigger, on the other hand not doing so means you still get mostly broken strings when it comes to end-user output.
- swah 11y agoArmin'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.
- Svenstaro 11y agoI'm using flask for my SPA with websockets just fine, though.
- mrfusion 11y agoSorry, what's SPA? And how are you using websockets with flask?
- ddorian43 11y agosingle-page-app you can do websockets with uwsgi for example
- Svenstaro 11y agoSPA: Single Page Application https://github.com/zeekay/flask-uwsgi-websocket https://github.com/zeekay/flask-uwsgi-websocket
- krat0sprakhar 11y agoKenneth Reitz has a popular extension for websockets with Flask - https://github.com/kennethreitz/flask-sockets https://github.com/kennethreitz/flask-sockets
- thearn4 11y agoFlask is an awesome framework. I've used a little bit of Tornado and Django for side projects, but found how overkill those were (at least for my small use cases) as soon as I got into Flask.
- simi_ 11y ago
- castell 11y agoWe 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?
- babo 11y agoIMHO they are just catchy titles to grab readers. As an example in the last sentence the author states: "I don't think there is a direct relationship between Python and Rust." That's a fair conclusion as TL; DR;
- pjmlp 11y agoFor me Python's only purpose in my workflow was scripting, I never considered it for application development. Nowadays that scripting urge is covered by Powershell/F# on Windows and OCaml/F# on GNU/Linux.
- bryanjos 11y agoI've switched from Python to Elixir. Python was my favorite language. I fell in love with functional programming after trying out Scala and spent a fair amount of time after trying out different languages to see which one was a good fit for me. Elixir is that language for me. When I start talking about it I seem to go on and on so I'll stop there. I'm also a fan of rust and plan to use it for more system level programming as well. I think its going to open the door to systems programming for more people and I'm excited to see what comes out of it. Also, as someone who has done a fair bit of C/C++, I'm happy to see an alternative.
- sophacles 11y agoI think it's that python has become a pretty big lingua franca of the programming world - so it makes sense that a lot of tutorials relate other languages to the one tons of people know already.
- tormeh 11y agoI 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.
- upofadown 11y agoThe 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 11y agoPython 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 11y agoUCS-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.
- bitL 11y agoA 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).
- okasaki 11y agoRust has much better performance.
- untothebreach 11y agoAs 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 11y agoI 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 11y agoI 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.
- juliangregorian 11y agoI think Julia gets unfairly pigeonholed. It's got a great concurrency story, for example. I know what you mean though, it always seems to be the language I'll write my "next" project in.
- mrfusion 11y agoIs that site down for anyone else?
- SimionBaws 11y agoCan 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.
- ynik 11y agoYes, here's a python module written in Rust: https://github.com/dgrunwald/rust-cpython/blob/master/extensions/hello.rs https://github.com/dgrunwald/rust-cpython/blob/master/extens... But anything more complicated than that (defining extension types etc.) isn't yet supported by the high-level bindings, and would need unsafe code using the python C API directly.
- sitkack 11y agoThis looks like it is tied irreparably to the CPython interpreter. One probably doesn't want to do this. Export a clean C compatible API and call via CFFI. This has the being callable from other languages, CPython and PyPy.
- mixmastamyk 11y ago^advantage of
- gthank 11y agoTL;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 11y agoThat 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-languages.html http://doc.rust-lang.org/stable/book/rust-inside-other-langu...
- swah 11y agoDo Rust newbies also complain about the lack of exceptions like in Goland (myself included even understanding their reasons..) ?
- pjmlp 11y agoNo because Rust offers a more natural way to deal with them, instead of ifs everywhere. Also known as railway programming in FP circles.
- platz 11y ago> railway programming in F# circles FTFY
- unmole 11y agoPretty sure pjmlp meant Functional Programming.
- platz 11y ago"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.
- progman 11y agoI 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 11y agoExpanding 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 11y agoRust 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).
- cgar 11y agoOn a completely unrelated thought, the second I saw the first three words of your paragraph, I thought of the infamous Kanye's interrupt. Not that I agree/disagree with your statement.
- bad_user 11y agoRust's goal is to be memory safe and high level without depending on a garbage collector, which is very important for many problems. That Rust is comparable with high level languages is a big accomplishment, as nobody compares C++ with these languages. Nim does not have the same goals. Which IMHO makes it a lot less interesting, because if you're allowed a garbage collector, then you can talk about Java / the JVM, .NET, Haskell, Ocaml, Erlang, Go and the list can continue.
- aidos 11y agoThat 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.
- the_mitsuhiko 11y agoYou can also use a locked data structure in Rust. This was to show how to actually use mutexes. In theory (assuming a Python with GIL or locked dicts) you can get rid of the mutex as well. But this only works for such a simple example in any case. The mutex generally works and was meant to show the relationship of the borrow checker and the mutability system to the mutex that moves checks to runtime.
- aidos 11y agoOk cool, I figured that was the case. I mostly sat down to write out the example to humour myself during my lunch break (as I said, I don't do much with threads so wanted to make sure I understood what was going on). The ownership/borrowing system is really interesting, not something I'd seen before - though I guess other languages do it too?
- 11y ago
- omouse 11y agoI 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.
- antman 11y agoI 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-cython/ https://honnibal.wordpress.com/2014/10/21/writing-c-in-cytho...
- synparb 11y agoHere 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.
- JshWright 11y agoFor 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...?)
- Profpatsch 11y agoDude, give the code some space. It can’t breathe cramped like this.
- caioariede 11y agoBetween 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 11y agoMaybe 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.
- Jweb_Guru 11y agoIt might also have something to do with the fact that Go has been out for five years and Rust 1.0 happened two weeks ago, or the fact that you are hearing about Go in different contexts from Rust because the two languages, despite HN's insistence to the contrary, aren't really appropriate for the same use cases.
- ForHackernews 11y agoAre there any good articles comparing the two? What are some contexts where one might be more appropriate than the other? I know Go's special focus is on concurrency. Is Rust less-good for concurrent applications?
- Jweb_Guru 11y agoRust is best viewed as a replacement for C++ in performance-critical, security-critical applications that are either resource-intensive, or exist in a resource-starved environment. In particular, it eschews garbage collection while preserving memory safety, even in the presence of multiple threads, something C++ does not. It also has native, overhead-free FFI-level compatibility with C. An example of where Rust is appropriate would be an operating system kernel, a video game, a web browser (writing one, not writing code that runs within one), embedded development, a high-performance database (there aren't any existing examples yet but it strikes me as an ideal language for this purpose), or fast, native extensions to applications written in higher level languages. Go is a relatively fast, ahead-of-time compiled, garbage-collected language; a good comparable for when you might want to use it would be OCaml (if you don't need threads) or Haskell (if you do). Java (particularly early versions of Java) or C# would also be a good comparable, in circumstances where you don't care about the JIT. Like Haskell, Go also has very good support for M:N threads, a particular threading model optimized for fast context switching and programmer ease of use (a common requirement for socket web servers). Unlike many ahead-of-time compiled languages, it also has compiler performance as an overriding concern--Go prides itself on its quick compilation. I would not say Go is better than Rust at concurrency. While Rust used to have M:N threads as well, it abandoned them because they turned out to have unacceptable performance tradeoffs in a language without a heavy runtime and garbage collector, and also play poorly with native code not managed by the runtime. Personally, I also feel that safe concurrency is considerably easier in Rust, where common Go idioms like channels are guaranteed to be memory safe, which they are not in Go with GOMAXPROCS > 1, and where it's impossible to see data races through things like mutexes or lockless data parallel threads in safe code. The reason to use Go over Rust would be that you can afford a garbage collector and a relatively heavy runtime, and are willing to accept some chance of data races (or don't require concurrency at all, or have a particular concurrent application where by far your biggest cost is context switching and you do very little allocation). This is the case for a large percentage of applications. Of course, there are many other languages available under these circumstances as well. I am not personally sure why people are espousing Rust for these applications, FWIW.
- whonut 11y agoAs 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 11y agoThis 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.
- Dewie3 11y agoRE: 1) : Smart people learn from their mistakes. But the real sharp ones learn from the mistakes of others.
- whonut 11y agoThanks for the reply. I'm leaning towards Rust. I'm required to learn C for university next year (I do physics) so I'm going to have to go through the pain anyway. There's also the quwation of usage in physics circles. It'll probably come down to the material I'm trying to learn each with. The Rust book looks very good, finding anything decent and modernish for C has been a nightmare.
- barosl 11y agoThis 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.
- Jweb_Guru 11y ago
- krick 11y agoBy 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 11y agoThe `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 11y agoIn 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)