News for hackers. Stuff that matters.
Re:The Case of a Leaky Goroutine by hedora on Monday March 25, 2024 @11:25AM (#39817502)
My #1 complaint about Rust is that leaking a future is safe. It means the compiler can’t check for async coroutine leaks, and it breaks the borrow checker’s ability to say “nothing else has a reference to this any more”.

Anyway, we’re using golang for some stuff at work, and holy crap, I forgot how terrible it was to work in high level languages that don’t statically check for correct synchronization.

If C++-style concurrency is like a chainsaw, then golang concurrency is like a chainsaw in a bouncy castle.

Re:The Case of a Leaky Goroutine by masklinn on Monday March 25, 2024 @11:50AM (#39817861)
> My #1 complaint about Rust is that leaking a future is safe.

There’s no other way given the leakpocalypse decision. You’d need an entirely new leak-proof language to fix that, and that means you need alternatives for Rc and Arc (or a way to prevent them creating a cycle).

Re:The Case of a Leaky Goroutine by hedora on Tuesday March 26, 2024 @11:19AM (#39829008)
I'd gladly give up Rc and Arc if it meant the borrow checker treated spawn() like a normal function call.

All the code I write is async, so the borrow checker is effectively broken for me. (Wrapping everything in Arc creates weird false sharing at runtime, and I don't want to spend time debugging that class of performance nonsense.)

Re:The Case of a Leaky Goroutine by f_gergo on Monday March 25, 2024 @11:39AM (#39817702)
What is a "correct synchronization"?
Re:The Case of a Leaky Goroutine by kccqzy on Monday March 25, 2024 @12:53PM (#39818587)
Synchronization such as the whole program is well-defined according to some memory model.
Re:The Case of a Leaky Goroutine by Thaxll on Monday March 25, 2024 @01:20PM (#39818933)
Which is the case for Go:

https://go.dev/ref/mem

Re:The Case of a Leaky Goroutine by kccqzy on Monday March 25, 2024 @03:29PM (#39820371)
A quote from your link:

> programmers are strongly encouraged to use appropriate synchronization to avoid data races

Any time you need to "encourage" programmers to do the right thing, you have already failed in your language design.

And I think OP agrees with me here. OP says "static checking of correct synchronization" which is irresponsibly absent from Go.

Re:The Case of a Leaky Goroutine by Thaxll on Monday March 25, 2024 @04:01PM (#39820653)
So it's absent from every language but Rust?
Re:The Case of a Leaky Goroutine by sapiogram on Monday March 25, 2024 @06:40PM (#39822055)
Javascript is even better, by not having multithreading at all. I am not joking, Go is much worse than Java and C#, but Javascript and Rust are the only mainstream languages where I've seen non-experts reliably write correct concurrent code. Maybe it's true for langauges like Elixir as well, but I haven't tried.
Re:The Case of a Leaky Goroutine by pdimitar on Monday March 25, 2024 @09:48PM (#39823478)
It's 95% true for Elixir as well; it's very difficult to mess up parallelization or just leave a system in an incoherent state with it. Immutability and message passing help a lot.
Re:The Case of a Leaky Goroutine by masklinn on Tuesday March 26, 2024 @01:22AM (#39824487)
My experience of JavaScript is nowhere near that good.

While it does not have parallelism, the concurrency is as unrestricted as it is in go, forgetting awaits is a very common issue leading to wild tasks running unbounded and unchecked, and when you need any other synchronisation mechanism you have to write them yourself and they’re tricky indeed.

$dayjob’s JS team keeps chasing concurrency issues, and breaking builds because of them.

Re:The Case of a Leaky Goroutine by kccqzy on Monday March 25, 2024 @07:37PM (#39822541)
Alternatively a language can choose not to expose anything low level enough to cause synchronization issues and only make available high level APIs that are correct by construction.

Go does neither. That's why there's this thread on HN that I bookmarked: https://news.ycombinator.com/item?id=31698503

Re:The Case of a Leaky Goroutine by hedora on Tuesday March 26, 2024 @11:29AM (#39829140)
I don't know of any other multithreaded systems programming languages that check for data race freedom at compile time.

Single threaded languages are usually data race free. I imagine some multithreaded, purely functional languages are too (everything is immutable, and therefore cannot be modified in race with reads). Of course, SQL running in strictly serializable mode is too.

Of those, the only one of those that's an appropriate choice for systems software development is Rust. The Core C++ Guidelines are a runner up in my opinion: They dictate a subset of C++ that is safer, with the goal of backporting the Rust memory safety properties to C++. Swift has also done a lot in this space.

Re:The Case of a Leaky Goroutine by duped on Monday March 25, 2024 @02:06PM (#39819469)
> My #1 complaint about Rust is that leaking a future is safe.

Do you mean futures that aren't polled to completion, tasks that aren't joined, or literal memory leaks that happen to own futures?

Re:The Case of a Leaky Goroutine by hedora on Tuesday March 26, 2024 @11:17AM (#39828979)
The first and third thing. (They're basically equivalent.)

You can start polling then do std::mem::forget on the future. At that point, the borrow checker thinks the future no longer exists. So, it is unsound to pass a reference with a bounded lifetime into a future (which is why you need all the references to be 'static if you pass something into a spawn, or you need to spray Arc everywhere).

Re:The Case of a Leaky Goroutine by duped on Tuesday March 26, 2024 @01:29PM (#39830509)
They're very different, because a future may be dropped before it is polled to completion (aka, cancellation). If you leak it, then the drop handlers are not called, and this can affect program correctness.

It is not unsound for a future to own a reference (in fact it's super common - how else would asnc methods work?). If you leak the future, it can't be polled and it can't be dropped, so any references will never be dereferenced. But also that's a pretty contrived example.

Like you could call std::mem::forget on a future that owns a tokio::sync::MutexGuard and then you'd have some problems with deadlock... but that's not an async issue, it's always incorrect to leak an RAII guard (same as if you leaked std::sync::MutexGuard)

tokio::spawn has a 'static bound because it simplifies things, not because there's some fundamental limitation of futures owning references.

Re:The Case of a Leaky Goroutine by favflam on Monday March 25, 2024 @11:23PM (#39824002)
For what it is worth, I totally agree. I programmed a fairly large project only to find that goroutines were mysteriously blocking in extremely hard-to-debug subtle ways. So, I had to rewrite a huge chunk. I think goroutines are like Ackbar "It's a trap" trap.

I was liberal in usage with goroutines and channels. But after that experience, I decided to religiously track each goroutine in my head. If I reached the point of not being able to mentally map all goroutines running, I would cut out go. I started using callbacks more too to avoid the pernicious blocking I have experienced.