original code was python with lots of C. the same can be done with Go, while keeping much of the same philosophy of python.
This change will probably alienate most of the contributors since rust and python or C are worlds apart.
original code was python with lots of C. the same can be done with Go, while keeping much of the same philosophy of python.
This change will probably alienate most of the contributors since rust and python or C are worlds apart.
Rust isn't hard. The only somewhat hard thing in Rust is writing with borrow checker, and honestly, if you want to seriously write in C, you really need to go through that experience and understand it enough to feel somewhat comfortable with it.
And even if that would really be a thing, giving up compiler checks in order to allow more low quality code to be contributed doesn't really seem like a good trade off to me.
Further, Mercurial is already 100% on the train of "giving up compiler checks," though "low quality code" is hardly a fair characterization of why.
Last I looked there wasn't a way to pin a pointer in Go and they explicitly forbid passing around opaque handles so you're already constrained in how you can interop.
Secondly you now have a whole nother runtime to hoist up instead of a simple C FFI. It hit this just recently with Python+Rust. Needed to optimize an inner loop. I could just drop down to a single Rust fn, write it and be on my way. No need to spin up a whole runtime just for that inner function.
The parent also hit it on the head. If you're going to be writing C you already need to understand lifetimes deeply, Rust just codifies that in a way that lets you catch it at compile time.
Deeply? Unlike complicated languages like for example GC-languages, C only has 2 lifetimes: block scope for stack variables, forever (until explicitly free'd) for heap malloc'ed memory.
You don't have to twist your head to know in which of N possible ways the data you get from a function was allocated, you don't have to twist your head to know if you need to free it manually, or semi-manually, or hope that it gets freed automatically at some point.
You don't have to care about stack variables, you just have to be organised about heap variables, and that's it. No complicated concept, not many different paradigms. You malloc() something to get some memory when you need it, you free() it when you don't need it any more.
Also you don't have to twist your head to know if you can access some function argument, if it was passed by copy or by reference or by a third mean, does it involve heavy data copying or not, what does it mean concerning access, etc. Everything is passed by value (copy) and you can only pass simple objects (plus structures), for anything else you pass the value of the address of the object, end of story.
To the contrary, C has just as many lifetimes as Rust. They're just not explicit. "free() it when you don't need it any more" is a complex problem and C doesn't really help you solve it at all.
> Everything is passed by value (copy) and you can only pass simple objects (plus structures), for anything else you pass the value of the address of the object, end of story.
That's how Rust works as well.
It's also faster, much more expressive, and much for flexible (e.g. for loading as a C-compatible lib) so there's that.
Go doesn't allow you to share pointers to Go objects with other languages/runtimes. So whatever else the pros and cons of each, working with Go from another language can be painful.
Yes, you can, but there are more constraints. E.g. you are also not permitted to pass a pointer to Go memory that contains Go pointers. There is a detailed description here:
https://golang.org/cmd/cgo/#hdr-Passing_pointers
Also, it used to be the case that cgo calls were relatively expensive (definitely not something you want to do in a hot loop). I am not sure if this is still true, but it was when I was using Go daily for projects.
EDIT: I don't mean to convey that GCs are still trivial in a mixed-runtime context; only that Rust is generally harder than Go.
As soon as GC'd pointers start passing across an FFI boundary you either need to:
1. Pin them and track yourself, which then loses a lot of your advantage of having a GC since you've got non-deterministic seg-faults based on when GC runs and pulls objects out from underneath you. C# lets you do this, but it's really painful to get right.
2. Prevent any GC objects being passed(which is what Go does). This means that there's a lot of things you can't do(esp with respect to callbacks and future events) that require a ton of gymnastics to do something that's trivial in C.
The rest of the Rust v Go debate may be similar to the 1000 times people have had it before.
The tricky part with two runtimes is (1) the system initialization and (2) the GC (if any) being able to control the initial stack frame. If you're just writing extension modules, either problem can be a challenge.
But the first problem goes away if you embed Python, as Python initialization is trivial for the host language when embedding. So does the second problem, as the host language is now in control of the initial stack frame.
The fact that a language is garbage-collected should not matter much; Python uses reference counting as its primary memory management mechanism, with a generational trial deletion approach for cycle colletion (which does not require root scanning). This approach can generally coexist well with a tracing garbage collector (though some challenges remain, but those can be designed around).
That said, Go specifically may have problems (I'm speculating here) due its green threads not being happy if Python does any blocking operations, and it's probably not safe to operate on Python objects concurrently in multiple threads. But that wouldn't necessarily be a problem for other languages.
When it comes to low-level, high performance, no overhead stuff and less unexpected behaviour C and Rust fit better.
Where high implementation speed and fast changing, experimental and highly modular architecture systems are more important C++ and Go are better.
For Mercurial and Git Rust or C makes more sense. Especially if you put experimental and fast changing stuff into a scripting language. IMO.
Go alone is easier than Rust. But since Rust has no GC, it is easier to embed, especially with a language with a Garbage collector like Python.
Go is intended to make it very easy for junior devs to build concurrent network applications. That's its design goal.
It's not a zero-sum game. Choosing rust doesn't weaken go or vice versa.
Really, There are so many other languages that are both performant and more readable than Rust (I consider Rust readability to be on par with C++).
With heavy FFI usage, that could become costly...