top | item 44698294

(no title)

jeeyoungk | 7 months ago

I like `gevent` but I think it may have been too hacky of a solution to be incorporated to the main runtime.

"creating the first ever first-class language with green-threading at its core."

... isn't that what Go is? I think out of all languages I use extensively, Go is the only one that doesn't suffer from the sync/async function coloring nightmare.

discuss

order

igregoryca|7 months ago

> the sync/async function coloring nightmare

I'm with you that function "coloring" (monads in the type system) can be unergonomic and painful.

> ... isn't that what Go is? I think out of all languages I use extensively, Go is the only one that doesn't suffer from the […] coloring nightmare.

Because it doesn't have Future/Promise/async as a built-in abstraction?

If my function returns data via a channel, that's still incompatible with an alternate version of the function that returns data normally. The channel version doesn't block the caller, but the caller has to wait for results explicitly; meanwhile, the regular version would block the caller, but once it's done, consuming the result is trivial.

Much of the simplicity of Go comes at the expense of doing everything (awaiting results, handling errors, …) manually, every damn time, because there's no language facility for it and the type system isn't powerful enough to make your own monadic abstractions. I know proponents of Go tend to argue this is a good thing, and it has merits. But making colorful functions wear a black-and-white trenchcoat in public doesn't solve the underlying problem.

(goroutines are nice, though.)

csande17|7 months ago

One of the largest problems identified in the original "what color is your function" article ( https://journal.stuffwithstuff.com/2015/02/01/what-color-is-... ) is that, if you make a function async, it becomes impossible to use in non-async code. Well, maybe you can call "then" or whatever, but there's no way to take an async function and turn it into something that synchronously returns its value.

But in Go, it's very easy to do this; you can just do "result := <- ch" to obtain the value from a channel in synchronous code. (This blocks the thread, but in Go's concurrency model this isn't a problem, unlike in JavaScript.) Similarly it's very easy to take a synchronous function and do "go func() { ch <- myFunction() }()" to make it return its result in a channel.

ashf023|7 months ago

All goroutines are async in some sense, so generally you don't need to return a channel. You can write the function as if it's synchronous, then the caller can call it in a goroutine and send to a channel if they want. This does force the caller to write some code, but the key is that you usually don't need to do this unless you're awaiting multiple results. If you're just awaiting a single result, you don't need anything explicit, and blocking on mutexes and IO will not block the OS thread running the goroutine. If you're awaiting multiple things, it's nice for the caller to handle it so they can use a single channel and an errorgroup. This is different from many async runtimes because of automatic cooperative yielding in goroutines. In many async runtimes, if you try to do this, the function that wasn't explicitly designed as async will block the executor and lead to issues, but in Go you can almost always just turn a "sync" function into explicitly async

pansa2|7 months ago

> I like `gevent` but I think it may have been too hacky of a solution to be incorporated to the main runtime

gevent's monkey-patching might be hacky, but an official implementation of stackful coroutines (similar to Lua's) need not have been.

Instead, stackless coroutines were chosen - maybe on merit, but also maybe because C#'s async/await keywords were in-vogue at the time and Python copied them.

dontlaugh|7 months ago

Stackless Python has existed for a long time. It’s “stackful” according to your definition, the term they refer to is the C stack.

progval|7 months ago

Erlang did it 20-30 years before Go