8 ms·
A Week with Mozilla's Rust
- chimeracoder 13y agoI don't want to turn this into a Go vs. Rust discussion, because the two languages are very different and have very different goals. However, I want to question the claim: > Go is also not particularly friendly to interface to external libraries written in C which doesn't seem to be explained anywhere in the article, and jars with my understanding. Go does play very well with C; cgo[0] makes this pretty straightforward. Maybe there are specific things that the author is trying to do that they found difficult in Cgo, but I would say that Go does play fairly nicely with C; that was a design goal. Here's a simple example of cgo in action: http://golang.org/doc/articles/c_go_cgo.html http://golang.org/doc/articles/c_go_cgo.html. As you can see, it's relatively straightforward and easy to use. [0] http://golang.org/cmd/cgo/ http://golang.org/cmd/cgo/
- dignan 13y agoI think it's more of a comparative statement. Interfacing with C in Rust is very simple, as he details in the article.
- derengel 13y agoThe keyword here is "friendly", which cgo really isn't.
- pjmlp 13y agoI never understood why they didn't went the Turbo Pascal/Delphi, Ada, Modula-3, .NET, D way and allowed for proper FFI declarations, instead of forcing a dependency into a C compiler that speaks Go calling conventions.
- acqq 13y agoRust not having the garbage collection as far as I understand can be made to produce routines that are part of C application. As far as I understand, by design Go can't be a "nice" citizen in a C application, the Go routine will bring with itself the whole city it lives in to your flat. So Go applications are something like "compiled, fast Ruby or Python." As far as I understand, Rust should theoretically be a way to write a piece of your application (even mainly C application) in something that gives you a different kind of expressibility. If there's need for that is another question, specifically, I'd like to see some examples that would really impress me. The examples the article author provided give me only the impression "OK it's weirder syntax but it's not so far from what would have to be written in C anyway, so where's the advantage?" What I consider missing for "properly" interfacing with C is for Rust to be able to slurp C headers as they are, without the need for additional "translation" files that are presented in the article. At least the headers without the definitions of the functions. But the declarations of the structures and functions and even basic preprocessing were really, really convenient.
- pcwalton 13y ago> The examples the article author provided give me only the impression "OK it's weirder syntax but it's not so far from what would have to be written in C anyway, so where's the advantage?" Memory safety.
- ZoFreX 13y agoAnd type safety, even when writing macros!
- stonemetal 13y agoAs far as I understand, by design Go can't be a "nice" citizen in a C application, the Go routine will bring with itself the whole city it lives in to your flat. That is correct, but the GP is correct as well. Using C code in Go is easy(just use cgo etc.), vice versa not so much(no such thing as goc etc.).
- Arnor 13y agoAt the bottom of the cgo command documentation [0] is an example of exporting go functions to C. I don't fully understand how those functions work when running in C land (does the GC come with?), but the implementation doesn't look difficult. [0] http://golang.org/cmd/cgo/ http://golang.org/cmd/cgo/
- timtadh 13y agoHow it works (from http://golang.org/src/pkg/runtime/cgocall.c http://golang.org/src/pkg/runtime/cgocall.c ) 36 // The above description skipped over the possibility of the gcc-compiled 37 // function f calling back into Go. If that happens, we continue down 38 // the rabbit hole during the execution of f. 39 // 40 // To make it possible for gcc-compiled C code to call a Go function p.GoF, 41 // cgo writes a gcc-compiled function named GoF (not p.GoF, since gcc doesn't 42 // know about packages). The gcc-compiled C function f calls GoF. 43 // 44 // GoF calls crosscall2(_cgoexp_GoF, frame, framesize). Crosscall2 45 // (in cgo/gcc_$GOARCH.S, a gcc-compiled assembly file) is a two-argument 46 // adapter from the gcc function call ABI to the 6c function call ABI. 47 // It is called from gcc to call 6c functions. In this case it calls 48 // _cgoexp_GoF(frame, framesize), still running on m->g0's stack 49 // and outside the $GOMAXPROCS limit. Thus, this code cannot yet 50 // call arbitrary Go code directly and must be careful not to allocate 51 // memory or use up m->g0's stack. 52 // 53 // _cgoexp_GoF calls runtime.cgocallback(p.GoF, frame, framesize). 54 // (The reason for having _cgoexp_GoF instead of writing a crosscall3 55 // to make this call directly is that _cgoexp_GoF, because it is compiled 56 // with 6c instead of gcc, can refer to dotted names like 57 // runtime.cgocallback and p.GoF.) 58 // 59 // runtime.cgocallback (in asm_$GOARCH.s) switches from m->g0's 60 // stack to the original g (m->curg)'s stack, on which it calls 61 // runtime.cgocallbackg(p.GoF, frame, framesize). 62 // As part of the stack switch, runtime.cgocallback saves the current 63 // SP as m->g0->sched.sp, so that any use of m->g0's stack during the 64 // execution of the callback will be done below the existing stack frames. 65 // Before overwriting m->g0->sched.sp, it pushes the old value on the 66 // m->g0 stack, so that it can be restored later. 67 // 68 // runtime.cgocallbackg (below) is now running on a real goroutine 69 // stack (not an m->g0 stack). First it calls runtime.exitsyscall, which will 70 // block until the $GOMAXPROCS limit allows running this goroutine. 71 // Once exitsyscall has returned, it is safe to do things like call the memory 72 // allocator or invoke the Go callback function p.GoF. runtime.cgocallbackg 73 // first defers a function to unwind m->g0.sched.sp, so that if p.GoF 74 // panics, m->g0.sched.sp will be restored to its old value: the m->g0 stack 75 // and the m->curg stack will be unwound in lock step. 76 // Then it calls p.GoF. Finally it pops but does not execute the deferred 77 // function, calls runtime.entersyscall, and returns to runtime.cgocallback. 78 // 79 // After it regains control, runtime.cgocallback switches back to 80 // m->g0's stack (the pointer is still in m->g0.sched.sp), restores the old 81 // m->g0.sched.sp value from the stack, and returns to _cgoexp_GoF. 82 // 83 // _cgoexp_GoF immediately returns to crosscall2, which restores the 84 // callee-save registers for gcc and returns to GoF, which returns to f.
- kodablah 13y agoWhat about callbacks to/from C code and function pointers? Embedding Go from C? Building shared libs in Go that can be loaded in C?
- jeremyjh 13y agoI believe he is referring to the fact that you cannot write a lib in Go that you link into a C application. Note that this is not just a matter of Go's GC and runtime requirement, but simply the fact that they do not support cdecl / stdcall conventions. There are plenty of garbage collected languages that can be linked into a C program (Lua, Python, even Haskell) - you just have to make extra calls to start-up the runtime.
- noloqy 13y agoThis question was answered by Armin Ronacher three days ago.[0] "Why for instance is it not a good idea to write a library in Go? The reason for this is that Go for needs quite a heavy runtime that does garbage collection and provides a scheduler for it's coroutines." [0] http://lucumr.pocoo.org/2013/8/18/beautiful-native-libraries/#which-language http://lucumr.pocoo.org/2013/8/18/beautiful-native-libraries...
- Goosey 13y agoI enjoyed the article as I haven't been exposed to much Rust yet, but I was disappointed that the intro didn't match the content The second sentence: > I want a language where I can be much more productive than in C: one in which I do not fear the correctness of my memory management, and don’t have to go through major gyrations to write concurrent code. And we see no explicit demonstrations of the memory management and no demonstrations at all of the concurrency model. It feels like the author had a more fleshed out post in mind, but either decided it was running too long or got bored before reaching the conclusion. :\
- relistan 13y agoA fair critique. I should write more on the subject.
- pohl 13y agoIt feels like the author had a more fleshed out post in mind, but either decided it was running too long or got bored... Or it could be that this post is just the beginning of his journey of learning & blogging about Rust. He did post another one 4 days later, albeit not yet touching on the topics you mention: http://relistan.com/a-pattern-for-wrapping-c-function-calls-in-rust/ http://relistan.com/a-pattern-for-wrapping-c-function-calls-...
- jkbyc 13y agoI agree, the actual content doesn't match the introduction so well. I've been looking into Rust during the past few days and I must say I got stuck on the memory model - all the different pointers and their interaction with ownership and mutability, closures capturing their environment (variables outside the closure in the scope where the closure is defined), reference binding, and then things like std::Cell which on the one hand seems to be an alternative to std::Option but on the other hand it's using some unsafe operations in its implementation to change mutability or something... It's quite confusing and it stopped me from writing a simple example application I wanted to write because I wanted to understand what's going on a bit better first.
- pcwalton 13y ago
- dkhenry 13y agoOf all the upcoming languages out there. I think rust is best positioned. The fact that it is really the only contender that can preform the same role as C, but it folds in lots of the language design theory of the past three decades puts it in a league of its own.
- catnaroek 13y agoExactly! This is what makes Rust exciting - as opposed to yawnfests like Go that merely provide a compiled, somewhat faster Python.
- dragonwriter 13y agoI like Rust and Go both, but I think that Go was intended not to be "exciting", but to provide a fairly narrow set of benefits and to be production ready quickly (I'm not really sure if the long term roadmap is for Go to stay there, or use production experience to grow into something with broader advantages, just carefully selected based on needs revealed through production use.) Rust is a longer-term, more ambitious effort.
- MrMan 13y agoagreed. no fan of Go.
- catnaroek 13y agoI am no fan of Scheme either, but at least I admit it had one big contribution: the idea that a language ought not to be measured by the number of its features, but by the number of things its features can express when combined. The situation with Go is completely different. Go is just... meh. Its concurrency model is worse than Erlang's, which predates it. Its type system is worse than Standard ML's, which predates it. Its runtime efficiency is noticeably worse than C++'s, especially so when using customized allocators and avoiding exceptions and RTTI. In short, Go is mediocre.
- Locke1689 13y ago
- reirob 13y agoI enjoyed the article very much. Please continue with your journey of explaining Rust to programmers that are looking for new alternatives to C.
- relistan 13y agoI really appreciate that feedback. Thanks!
- klibertp 13y agoThe example of match usage is really poor. From the looks of it there is no "pattern matching" going on at all here. I don't know the syntax, but even something like this would be a better demonstration: let computed_key = match (key.len() > self.block_size, key.len() < self.block_size) { (true, false) => self.zero_pad(self.hash(key).digest), (false, true) => self.zero_pad(key), (false, false) => key } At least there is some matching here, unlike in the original example. But in real world this should be if..else if..else statement, not match - the latter being used makes no sense if there is no matching going on. In Erlang there is an if statement, which is a 'case' (equivalent of match here) but with matches taken out and only guards allowed - that's what would fit here, but I doubt Rust has something like this. Also, does the compiler complain about my example above being not exhaustive? I think in OCaml it would, which is sometimes nice.
- masklinn 13y ago> Also, does the compiler complain about my example above being not exhaustive? Yes, although the error message isn't very good: crypto.rs:55:23: 59:5 error: non-exhaustive patterns: true not covered crypto.rs:55 let computed_key = match (key.len() > self.block_size, key.len() < self.block_size) { crypto.rs:56 (true, false) => self.zero_pad(self.hash(key).digest), crypto.rs:57 (false, true) => self.zero_pad(key), crypto.rs:58 (false, false) => key crypto.rs:59 }; error: aborting due to previous error And technically that's not a good thing, since (true, true) is not possible considering the input.
- lambda 13y agoThat seems like a really bad example of pattern matching, as no pattern matching is going on; it's just using the guard statements, and so could be replaced with an if statement: let computed_key = if key.len() > self.block_size { self.zero_pad(self.hash(key).digest) } else if key.len() < self.block_size { self.zero_pad(key) } else { key }
- scribu 13y agoSo the last statement in a block for a matched if condition gets assigned to the variable? That's pretty cool.
- kibwen 13y agoBy leaving off the semicolon, you can make a block (which is anything in braces) evaluate to the value of its final expression. It's one of those rules that seems perfectly terrible at first blush, but actually seems to work really well in practice thanks to Rust's strong static typing.
- rybosome 13y agoAny language that emphasizes expressions over statements will have this feature. Off the top of my head, that should include Haskell, Scala, CoffeeScript, Ruby, Elixir, Clojure (hell, anything Lisp really)... The idea is that while you may be able to traverse code-paths with side effects in some of these languages, they encourage treating a line of code (term used loosely, as an expression can span multiple lines) as a computable value. It may take a bit of getting used to at first, but from my own experience, it now feels weird and awkward when a language doesn't. Reminds me of looking at a nasty language like MUMPS or something, where persistence is built into the core language; statement-oriented languages tend not to be composable.
- regis 13y agoRust looks really great and I would love to switch all of my C development over to Rust but last time I tried to compile it, it took a good hour or two. Has this changed at all?
- pcwalton 13y agoWell, we have a production-quality optimizer (LLVM). So it'll always take some time to compile. Eventually once all of our LLVM patches are upstream and the versions including the patches make it into common repositories you may be able to use your system LLVM to compile the Rust compiler, at which point the compile times will drop dramatically. We continue to work on compile speed of Rust code all the time.
- copx 13y agoWill you also work on providing a better Windows package? I don't understand why you don't just bundle all the dependencies, given that they all seem to be open source and redistributable. Call me spoiled but I expect a one-click installer in this day and age. I still haven't tried to actually use Rust because of that and I am sure I am not the only one.
- anon3132 13y agoWhy bother working on a proper distribution of a package that isn't anywhere near ready? It will come in its due time.
- dbaupp 13y agoYou're spoiled :P But, windows is (unfortunately) a bit of a second class platform at the moment (although there have been some very big strides in the last week or so). So part of the reason for poor windows packaging is Rust isn't ready on windows yet (even more so that its normal pre-alpha-ness on Linux and Mac).
- pjmlp 13y agoI hope Rust can eventually reach compile speeds of most module based languages. Every time I update my netbook with a new Rust release it takes a few hours, it almost feels like I am compiling KDE or something.
- general_failure 13y agoWhy do people keep reinventing syntax? Quick tell me what the following mean: struct Digest { digest: ~[u8] } // what's ~ here? for self.digest.iter().advance |&byte| { acc = acc.append(fmt!("%02x", byte as uint)); } acc What does the above mean? acc as a separate line and nothing else I hate it when people reinvent the same construct that can be found in other languages but differently. I guess they want to do something different in their language, is it?
- mcpherrinm 13y agoRust does have some new syntax, but I think most of it is justified for making programming in it nicer. The `~[u8]` would be written `std::unique_ptr<u8>` in C++. They're used everywhere in Rust, and having to write out unique_ptr would get awfully tiresome. The `acc` on its own line is a result of "the last statement gets returned" like many functional languages do. If you were writing C++, you'd write `return acc;` instead. This one is more of a convenience, and you could get away without it.
- masklinn 13y ago> The `~[u8]` would be written `std::unique_ptr<u8>` in C++. Wouldn't it be `std::unique_ptr<std::vector<u8>>`?
- mcpherrinm 13y agoIndeed, it would.
- userulluipeste 13y agoI agree that C++ broke the syntax terseness of C and become verbose for the sake of being explicit enough. This gets inconvenient sometimes, but the good thing is that it is a technical solvable problem - just redefine the long keywords or configure your editing tools to help you out typing.
- lifthrasiir 13y agoIt indicates ownership. If you know C++, ~T in Rust is similar to std::unique_ptr<T> in C++ (ensures that there is only one owner of given value) and @T is similar to std::shared_ptr<T> (ensures that there are one or more owners of given value and the value would be deallocated when the last owner vanishes). But you can't check the correctness of these "smart pointers" in the compile time in C++ while keeping the efficiency; Rust has both the correctness and efficiency (1) by making these important types to built-in constructs. (1) Still being worked on.
- gnur 13y agoI don't think it's fair to compare Rust to Go, while operating on nearly the same level. They are targeting a very different crowd. Go has very clean syntax, few reserved words and writes almost as easy as python. This makes go a attractive language for programmers who have a history with languages like php & python but also want more speed. Rust on the other hand has a more complex syntax but allows you more control over memory, thus making it more attractive for those with a history in C or C++. Go is a good language to learn as your first compiled language, easy to write, easy to learn and a good ratio between performance and effort. Rust is (or will be when it's stable) a good language to learn when you have a history in C and you want memory & type safety but still the control you are used to in C/C++.
- buster 13y agoI must say i am really surprised about the presented features of the language. It seems to take a lot of the nice things of more dynamic languages and puts them into a fast, compiled system language. I will have to try Rust, now!