Earlier quoted context omitted.
> And, it absolutely should not require creating two identical function definitions to get around the function coloring problem - that's completely indefensible. I'm afraid I don't follow. It's impossible for you to have two identical functions (one sync and one async), since then they would both be sync. What did you mean?
Two functions that are identical up to one of them being async and using "await" to call another function foo_async, and the other that is sync and calling foo_sync (a synchronous version of foo_async) without await?
Ruby methods are colorless
111–120 of 242 posts
Re: Ruby methods are colorless
#112Earlier quoted context omitted.
Two functions that are identical up to one of them being async and using "await" to call another function foo_async, and the other that is sync and calling foo_sync (a synchronous version of foo_async) without await?
I think the only place that happens is in programming languages where you actually can choose to do something using a thread-blocking operation? Specifically, I've only seen it in Python. And yeah, it's not very ideal there. In other languages, it's typically only possible to do the operation in async mode, so you never write a foo_sync function in the first place.
Alternately, I want to be able to designate a computationally-intense function call (just that call, leaving the other calls alone) as async so that control yields to the event loop.
The main problem is that someone got it in their head that the function definition was the right place to designate whether a function was async or not, and it's not. The right place is the call site.
Re: Ruby methods are colorless
#113Earlier quoted context omitted.
> Aren't all these calls blocking? Only locally, which is pretty much the same as when you `await` a call. > Threading vs an event loop are two different concurrency models. The point is that you can build a "threading" (blocking) model on top of an event loop, such that you get a more natural coding style with most of the gain in concurrency. It loses some, because you only have concurrency between tasks (~threads)…
The whole point of async/await is to allow for not blocking the caller though until it's ready for an explicit synchronization point. If you are blocking the caller you have not "solved" the colored function "problem".
Re: Ruby methods are colorless
#114Long-time JS/TS/Node programmer here. Knowing ahead of time which functions are async is a feature . It's a big neon sign that says "hey, this function call is expensive ". This is a good thing for programmers to easily see and know at the call site. If you make multiple calls with async/await in a row, the performance issues are plainly obvious at the call site. With "colorless" functions, this information is hidden…
> is a feature I was quite shocked to read this, as in it never brushed my mind that it could be. I personally doesn't feel like it is and is one of the reasons why I try to avoid working with that stack at all cost. I don't think the neon sign is a good excuse for the mess colored functions are. You easily can create a synchronous O(n^4) function, and there are probably tons of quick async functions. Moreover, your…
No, source code is where you hide the information, documentation is where you hide misinformation (or accurate information about how the function worked 3 versions ago, which is much the same thing).
Re: Ruby methods are colorless
#115Long-time JS/TS/Node programmer here. Knowing ahead of time which functions are async is a feature . It's a big neon sign that says "hey, this function call is expensive ". This is a good thing for programmers to easily see and know at the call site. If you make multiple calls with async/await in a row, the performance issues are plainly obvious at the call site. With "colorless" functions, this information is hidden…
> Knowing ahead of time which functions are async is a feature. "Expensive" is subjective and should be up to the programmer to decide. And, it absolutely should not require creating two identical function definitions to get around the function coloring problem - that's completely indefensible. > This is a good thing for programmers to easily see and know at the call site. Yes, and the IDE can show you that informati…
Oh yes, absolutely. But the solution to that is stop using joke languages that can't do kind polymorphism.
> Yes, and the IDE can show you that information, exactly like it does the types of arguments.
How can it, if the language doesn't give it that information? Either you have a language that can reliably distinguish between sync and async calls in a standard way - which is to say, it has a type system that distinguishes between sync and async, whether it calls it that or not - or your IDE has an ad-hoc informally specified bug-ridden slow implementation of half of one.
Re: Ruby methods are colorless
#116Earlier quoted context omitted.
Ruby/rails is full of shortsighted crap like this. I feel stuck, our whole backend is legacy rails and I can’t escape.
Bit of a strong claim when the Erlang/OTP was designed to handle massive concurrency without colorful methods. Given that both Erlang and Ruby are inspired by the message passing semantics of Smalltalk.
Re: Ruby methods are colorless
#117As they should be. I object to doing what a computer can do for me (in programming), and manually creating separate versions of functions that are identical up to async absolutely falls into that category.
Re: Ruby methods are colorless
#118Earlier quoted context omitted.
Of course, the other nice thing about the JS example compared to Go is that it's trivial at the callsite to do this: const [[rA, errA], [rB, errB]] = await Promise.all([ engine.doSomethingWithA(), engine.doSomethingWithB() ]) At least these days you can ask an LLM to write the WaitGroup boilerplate for you in Go.
Yeah, go's a little boilerplatey, but you have to option to run two sync things concurrently as well with something like: type result[T any] struct { el T err error } chanA := make(chan result[aResultType]) chanB := make(chan result[bResultType]) go func() { defer close(chanA) a := &blah{} rA, err := engine.doSomethingWithA() chanA
Re: Ruby methods are colorless
#119Earlier quoted context omitted.
Of course, the other nice thing about the JS example compared to Go is that it's trivial at the callsite to do this: const [[rA, errA], [rB, errB]] = await Promise.all([ engine.doSomethingWithA(), engine.doSomethingWithB() ]) At least these days you can ask an LLM to write the WaitGroup boilerplate for you in Go.
Yeah, go's a little boilerplatey, but you have to option to run two sync things concurrently as well with something like: type result[T any] struct { el T err error } chanA := make(chan result[aResultType]) chanB := make(chan result[bResultType]) go func() { defer close(chanA) a := &blah{} rA, err := engine.doSomethingWithA() chanA
func runTask[T any](task func() (T, error)) chan result[T] {
ch := make(chan result[T])
go func() {
defer close(ch)
res, err := task()
ch
Does that sort of thing happen much in practice?Re: Ruby methods are colorless
#120Earlier quoted context omitted.
> Aren't all these calls blocking? Only locally, which is pretty much the same as when you `await` a call. > Threading vs an event loop are two different concurrency models. The point is that you can build a "threading" (blocking) model on top of an event loop, such that you get a more natural coding style with most of the gain in concurrency. It loses some, because you only have concurrency between tasks (~threads)…
The whole point of async/await is to allow for not blocking the caller though until it's ready for an explicit synchronization point. If you are blocking the caller you have not "solved" the colored function "problem".
That is an end not a mean.
Again in my experience the vast majority of devs could not give less of a shit about “not blocking the caller” by default. What most devs want is a reasonably cheap way to get a high amount of concurrency.
If anything not blocking the caller by default is generally an error, because somebody forgot an await.
> If you are blocking the caller you have not "solved" the colored function "problem".
Of course you have: you have solved the actual problem that needs solving without using function colouring. That’s how e.g. Go works. Go has problems up the ass but it doesn’t have that one at least.
Java is also moving back to Userland threads rather than towards async/await.