Hacker News new | past | comments | ask | show | jobs | submit login
Rustgo: Calling Rust from Go with near-zero overhead (2017) (filippo.io)
107 points by ingve 81 days ago | hide | past | web | favorite | 37 comments

A nuance I wish I had expressed better in this article is that it's targeting functions that would otherwise be written in assembly: they'd have to be quick (not to undermine the scheduler) and non-recursive (not to blow the stack). For just calling larger Rust functions one can use cgo.

+1. There's a reason cgo sets up another stack; calling into Rust instead of C doesn't change that.

What are the consequences if you blow the stack in Go [edit: to clarify, I mean if your code in another language that doesn't understand Go's stack copying calling convention blows Go's stack]? Is there a guard page (so SIGSEGV) or does it just corrupt memory?

If you have to reverse-engineer the undocumented Go calling sequence to call Rust, you probably shouldn't be using that for security-critical crypto functions. The next time somebody changes something, there will be trouble.

This is especially an issue in a garbage collected language. If the only reference to something was passed from Go to Rust, will Go's GC marker find it? If it doesn't, everything will work just fine, until someday a garbage collection happens at the wrong moment.

In security critical code, that's probably exploitable if you can force a GC from another thread.

> If the only reference to something was passed from Go to Rust, will Go's GC marker find it?

No, and rightly so. I would expect https://golang.org/cmd/cgo/#hdr-Passing_pointers to apply just as much here as with CGo (the criteria is "foreign allocator", not CGo).

Which is a problem here, because the OP is calling Rust from Go using the Go calling sequence. So Go's checking doesn't know it's calling non-Go code. There's a defined way to call C from Go, but the OP is not using that interface.

It's fine as long as you don't store Go pointers in non-Go memory.

If the local variable is the last reference to the thing, https://golang.org/pkg/runtime/#KeepAlive makes sure the Go side doesn't drop it before the call is complete.

> I'll be upfront: I don't know Rust, and don't feel compelled to do my day-to-day programming in it.

I wonder if this changed. A quick glance over the blog hints me towards a no.

It's a statement that is ~ 2 years old. I recently started learning it and like many things about it. I also haven't learned enough, so any borrow checker annoyance is likely a symptom of not knowing enough.

So far, I like:

- traits (similar to typeclasses)

- support for functional programming

- borrow checker keeping you aware of memory scoping

- it's (apparently) fast and relatively lightweight

Rust is great. It's nice to have an efficient way to call Rust code from Go for when you need that extra speed and security.

I was just curious if Filippo's stance changed about the language since he works with cryptography and security at Google. I'm not seeing Rust in his GitHub repo's https://github.com/FiloSottile

I've been considering using Julia and rust in this way. anyone tried that?

I've used it. Julia's ccall is so nice to work with once you have wrapped it in other functions. The hardest part was creating, finding, downloading and using the right library with it's dependencies during Julia's build step for a package.

Out of curiosity, what sort of code aren't you able to write in Julia that you can in Rust?

the idea was more to get that extra bit of speed for profiled bottlenecks. not a need, more a want. benchmark game currently puts Julia on par with go, not rust. also it seems to forgo simd except for obvious cases with large arrays.

Yeah. I think the benchmark game entries for Julia are unfortunately poor / stylised - IIRC there was a fork that delivered actually fast implementations (at the cost of some prettiness), but I don't think it ever got merged in.

I do agree that there a few cases where Julia in theory could do what you wanted, but it's a bit awkward to get the guarantee from the compiler that it will do so (e.g. SIMD this thing, constexpr this thing..). I do hope this situation improves.

It's really quite easy to guarantee the compiler uses SIMD in Julia, it just takes a bit of reading the docs and understand the Zen of Julia.

I would like someone good at Julia to tighten up those programs. benchmark game still takes submission right?

I updated the Julia n body problem to use simd. It's actually really easy to read and I'm pretty confident it's very performant, but the problem is that for the number of iterations done, the VM boot time dominates. If you were doing a problem IRL, you would expect run times in the hours, and a 5 second vm load and program compile penalty would be peanuts.

which implementation is that? 2 is the fastest but it doesn't use any .* or the like, an 3 which does and has "vectorised" in the comments is actually half the speed of 2

That line pretty much sums up the experience a lot of devs feel towards Rust

This is how most devs feel about any language they don't already use. There are even HNers who regularly brag about having never taken Javascript, one of the most ubiquitous languages, seriously enough to build a nontrivial project or to appreciate its upsides.

So it's not as damning as you seem to suggest.

For web dev, the ecosystem isn't quite there yet. I've written a few utilities and toy APIs, but don't feel like the web ecosystem is was rich as it needs to be for a serious project. Actix comes close. A few others like Warp ND Gotham are interesting. I'm waiting for rocket to compile in stable, and pick up async.

But yes, rust is definitely pretty cool, and I'm annoyed that I finally "understand" the language on my nth attempt at learning it, and still haven't found a good use case for it.

I’ve been thinking recently about how the symbol “C” in “C programming language” literally stands for “3”.

We out here like, “I’ve been getting really into this new language, 12,447. I think it might finally be the thing to replace 3 for me.”

Except it wasn't the third. It was like something between the 50's and low 100's. There were lots of languages then, most being unpopular.

C was just intended to be third in that very specific lineage, and I wouldn't be surprised to find it wasn't really third and just making the claim with its name.

>There were lots of languages then, most being unpopular.

Not to mention several more advanced than C, Go, or even Rust... (Lisp, for one, Smalltalk for another)

Well, it depends on what you mean by advanced, and if you're just considering the language or language plus compiler/runtime, but I take your point, and mostly agree with it.

General purpose languages are a tough sell these days. Rust is tailored towards a niche and that's OK

> Rust is tailored towards a niche and that's OK

I encourage people to try writing run of the mill blocking code with Rust instead of diving immediately into futures and thread pools and streams just as if you were writing run of the mill Python.

It's generally 1:1 equivalent to the code I would've written in another language.

It's a general purpose programming language where most of the learning curve is in more advanced topics like concurrency, streams, and how to multiplex over thread pools. You can ignore them at the start, just like you can in Python.

Systems Languages are considered niche these days?

But it's not the first systems language, so it does need to carve a niche in that space

What is Rust's niche? What excites me about it is that it is becoming a general purpose ecosystem. A few libs are missing, but that's changing rapidly.

Of course generally the ones who “don’t know it”. But then that probably holds true for all languages one does not know.

I was a big fan of Rust at first. Then they went off into a weirdo approach to functional programming. That sent Rust to the niche in which Haskell lives.

You'll have to be a bit more specific, I've been using the language for quite a long time now and I don't understand what you're referring to. I haven't noticed any obvious paradigm shift since 1.0.

Filippo also gave a talk at GothamGo on this subject: https://www.youtube.com/watch?v=eymMKjymgGA

I've been finding learning Rust an extremely valuable experience and I really like the language. Also I don't have any experience with replacing assembly code with a higher-level language. But...

If you're looking for a replacement for hand-crafted assembly, don't the strict lifetime-checker and borrow-checker make Rust a non-obvious choice? E.g. they might prevent you from doing certain memory access patterns that you actually explicitly want your assembly to do? (I.e. wouldn't C or C++ be more the thing?) Or do you just make liberal use of unsafe blocks where necessary? Or is it actually fine and appropriate to write {lifetime,borrow}-checker compliant replacements for hand-crafted assembly?

Previous discussion: https://news.ycombinator.com/item?id=15017519 (68 comments)


Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact