Rust for Python Programmers
lucumr.pocoo.org
lucumr.pocoo.org
I can't think of a single WTF moment I had with it. Several "OMG this guy thought about this too" moments.
you can do websockets with uwsgi for example
edit: Thank you for your reply - by the way yes, I am indeed only building a REST API.
EDIT: Both are very good.
If you started out parodying something else you didn't like, and ended up completely emulating its interface, it means that you were either wrong earlier or you were wrong later.
Maybe he will do better things in Rust, but Flask has been heavily overrated since it came out.
I ask not because I want to be snarky, but because I don't have the breadth of experience to identify any of the deficiencies in the Flask design. I'm curious to learn more.
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...
At the moment, it's chosen to be 6: https://doc.rust-lang.org/src/collections/btree/map.rs.html#... (note the FIXME though).
I consider Nim the "better Python", and Rust the "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.
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).
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.
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 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.
The ownership/borrowing system is really interesting, not something I'd seen before - though I guess other languages do it too?
for t in threads: t.start()What's strange is that I didn't even consider writing the for loop on a single line. I just never do that. It's clearly better in this case (than a list comprehension). In real code I'd just do it on 2 lines.
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.
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.
This is not adorable. This is a license to make programmers who come after you experience a kind of living hell.
This is why you use "except Exception:" which doesn't catch system exceptions.
Or so it seemed to me.
Unfortunately there's no common parent to EnvironmentError/SystemError/RuntimeError/etc that excludes SyntaxError.
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).
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.
I also have Julia in my mind for my next scientific computing (image processing, DSP) project.
In comparison, Julia has relatively few web frameworks, GUI toolkits, etc..
* harder, but not impossible
https://github.com/micklat/NimBorg
I've been able to call into the Nim side from Python by treating the Nim code as C functions to call. That works, but it would be interesting to come up with a more Pythonic way of doing that.
Rust is for performance critical applications where you cant afford garbage collection. You would choose Rust as an alternative to C or C++.
Using Rust will certainly not make your life easier compared to Python. But you could use Rust on some projects where Python is not possible.
To me, at least, Rust provides a compelling alternative to C in the Python+C combination. Coming from Python, writing C is pretty unergonomic; it's super-easy to shoot yourself in the foot and have your program die with an inexplicable segfault, which feels pretty alien for someone used to nice pretty stack traces. Rust promises to make that a lot more pleasant by being memory-safe, while still making good performance promises.
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.
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.
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.
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 )
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.
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.
Or if you're using a native code compilers (not sure about C#, but they exist for Java).
Most people writing web apps don't need a language where you have to worry about ownership, but they do need a language that does concurrency really well. It's the same reason you hear more about Python or Ruby than C++ here. Use cases.
Even as Rust matures, it is unlikely that people will be writing a lot of web apps in it.
Other than the "Go is more relevant to the crowd here" which is a bit overarching, I don't see what's wrong here.
I'm a Python user that has my eye on Go instead of transitioning to Python3, but letting Rust/Go/Py3 all bake for a bit before doing anything (though Py3 is last on that list as I've lost faith in it at this point). I tend to agree with his viewpoint. Do go on.
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.
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.
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.
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.).
Go/Rust/Erlang/Elixir/Node/Nim/Julia for Python programmers
Is there a trend away from Python2/3 or Ruby to language X?
Nowadays that scripting urge is covered by Powershell/F# on Windows and OCaml/F# on GNU/Linux.
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.
[1] I don't know if I've seen enough designers' opinions about it to say anything.
For me, Go has problems (as Python does) but thus far I find it the most appealing of all choices. I tend to be attracted to simpler things (worse is better).
"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...?)
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.
Smart people learn from their mistakes. But the real sharp ones learn from the mistakes of others.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.
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.
These are going to be the same in C anyway so I wouldn't decide whether to learn Rust or C based on that.
[1] See eg: https://github.com/incrediblesound/Graph-Reply/commit/929e57... for a little bit about C and warnings.
That said, even the author of LCTHW (Zed Shaw) recommends writing in languages other than C. He specifically mentions Go, Swift, and Rust.
Check out his rant on K&R C at the end of LCTHW for his thoughts on your question: http://c.learncodethehardway.org/book/krcritique.html
C and C++ really isn't the same thing. Certainly not "modern" C++. Unless you know of any C++ projects/frameworks/libraries you really want to use/contribute to -- I don't think I would recommend looking to hard at C++. It certainly isn't a dead language, and has many uses -- but at least outside of the gaming industry, I can't think of any segment were C++ would be the preferred language -- except when dealing with legacy code (which of course, realistically is the biggest segment...). Perhaps C++ paired with qt for GUI programming.
But even for games, you don't need C++ -- if you are free to start from scratch anything will work.
> is Rust a decent place for me to learn lower-level concepts
Which lower level concepts?
C maps quite neatly to assembler -- but to appreciate that I'd recommend learning a bit of assembler. amd64 with nasm/intel syntax is rather pleasant[1]. It'll let you see what calling conventions/ffi, data layout and the difference between c-strings and pascal strings are all about.
If you take a canonical hello-world from C, C++ and rust and look at the generated assembly -- rust and c++ will be (IMNHO) closer to each other than to C. The assembler generated by the c-compiler will be straight forward, and quite readable -- while both C++ and rust will look a little more convoluted. (This is also true for Nim, which compiles to C -- but needs it's own runtime. I've not looked too hard at code generated by go -- but given the runtime, I think that assembly would also be much more difficult to make heads and tails of, than something output by a C compiler).
If your goal is more to learn a low-overhead compiled language, I would recommend rust. If your goal is to find a compiled language that is easy to integrate with others, I think I would recommend C (for now) -- and a bit of basic assembler.
I think after learning a bit of assembler and C -- one also gets a better appreciation for why Pascal was so popular for a while.
With any luck, and more work -- hopefully rust will be able to sneak into quite a few of Cs use-cases, like writing libraries for easy consuption by python/ruby/etc. But I don't think rust is quite at a place where it makes sense to reccomend it for that use-case to a novice (low-level) programmer. I'd love to be wrong about that.
[1] Unfortunately, I don't really know of any good introductions to amd64 assembly. There are a couple of great tutorials for 32bit/x86 -- but a lot of things are simpler in our amd64 world. While it might be good to know how to write bootloaders (16bit) and 32bit code -- I'd love for there to be a simple tutorial focused on just amd64.
I like this asm tutorial (unfortunately for 32-bit):
http://www.drpaulcarter.com/pcasm/
And "HLA" is another great resource for 32-bit assembler:
http://www.plantation-productions.com/Webster/www.artofasm.c...
Sadly, neither have been ported/updated to a version with a focus on amd64 only.
Intel has an ok overview article focused on 64-bit:
https://software.intel.com/en-us/articles/introduction-to-x6...
Can you expand on why that is, maybe?
http://cffi.readthedocs.org/en/latest/overview.html#simple-e...
And, under IPython (python3) on Windows (I already had ms visual studio installed):
import pip
pip.main("install cffi".split())
> (...)
> Successfully installed cffi-1.0.3 pycparser-2.13
from cffi import FFI
ffi = FFI()
ffi.cdef("""int printf(const char *format, ...);
""")
C = ffi.dlopen(None)
arg = ffi.new("char[]", b"world")
C.printf(b"Hi there, %s!\n", arg)
> Hi there, world!
> 17
So a lot of this is tooling, integration and documentation.If one might whip up something similar for rust that works cross platform, and results in code that is reasonably easy to distribute via pypi (and similar for gems for ruby etc) -- that'd be great.
So, I meant that for a novice, that wants to, say write a compiled extension/wrapper for python/ruby whatever -- a bit of C and the standard docs go a long way now.
Obviously there's a lot of work to get to the point of C (it's been ubiquitous for a while...) -- but if some parts could be made similarly accessible; interfacing with rustc, if rustc is in path/installed "properly", some magic on the host-language side etc -- that would be very good, I think.
I'll have a look when I find the time - but this is a great start!
Yeah, things like "what do I do about more complex types" needs tons of more docs in general. We will get there. I'm also pretty convinced that a dedicated individual could create pretty awesome automatic binding generators for any language, especially since bindgen works pretty well for C... but we'll see how it shakes out.
Don't hesitate to email me or post in the forums if you play around with this and get stuck :)
> Which lower level concepts?
I may be misusing the terminology but I had in mind the sorts of things Python does for you, like memory management.
> If your goal is more to learn a low-overhead compiled language, I would recommend rust.
Now that you mention it, this is probably the main thing I want. Integration with Python would be nice though and, as mentioned in a previous comment, I have to learn C for university soon anyway.
"Learning Standard C++ as a New Language" http://www.stroustrup.com/new_learning.pdf
Rust has great documentation that's rapidly improving, but the selection of "syntactic tools" are somewhat eclectic -- yet I think one could probably be a better C programmer by first learning Rust (just as one might be a better C programmer by first learning Pascal and/or Ada) -- precisely because Rust has gathered up what seems to me to be a very useful subset of "things" (borrow/box, strong typing, safe/unsafe etc) -- that can be useful to apply to any kind of programming.
And just as with C++, Rust will give you somewhat more complex solutions (if you look at the generated machine code) than naive C code -- but as it turns out -- the naive C code is probably incorrect, anyway!
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?
For example, the io library generally returns 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://blog.burntsushi.net/rust-error-handling/
(which was posted to hn a while back)
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.
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.
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
There's no such thing as UCS-16 or UCS-32.
Also known as railway programming in FP circles.
FTFY
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.
Rust is less functional than Haskell or Scala, so I don't know how that works out, but in FP languages it ends up working great. Also, compared with Go it isn't the same thing.