Live data from Hacker News

Ruby methods are colorless

jpcamara.com

191–200 of 242 posts

Re: Ruby methods are colorless

#191
post #81

Long-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.

It can be, but this fact doesn't always scale well to larger APIs over time.

If you see that a function is async, any of these could be true:

1. The function does some asynchronous work.

2. The function did some asynchronous work at some point in the past, but does no longer, but changing the signature is a breaking API change, so it still looks async.

3. The function does no asynchronous work, but it's a public API and the library maintainer thinks there is a good chance it may need to do async work in the future so made it async today to reserve the right to make that change without breaking the API.

4. The function may or may not do asynchronous work, but it's part of an interface that others are allowed to implement and the designer of the interface wants to give implementers the freedom to make their implementations async if they want.

5. The function is higher-order and wants to be able to accept callbacks that are themselves async.

There are probably others I'm forgetting.

This all sounds hypothetical but it's really not. If you maintain any widely-used long-lived package, you run into design questions like this all the time.

There is always a tension between an API consumer wanting to know what a function "really" does versus the API author wanting some abstraction so that implementation details can be changed over time without breaking users.

Asynchrony is one kind of effect or observable behavior that a user/maintainer of an API may or may not want to encapsulate, but it's not the only one. The C++ standard library documents and commits to the algorithmic complexity of most functions. Haskell function signatures pin down whether or not a function does IO. Statically typed languages pin down the types parameters must be.

Pinning down more of this stuff gives the API consumer some more information, but it's not always a pure win. It calcifies the behavior of the function in ways that can harm its evolution or interact poorly with higher-order code or polymorphism. There's no silver bullet.

Personally, I've never found "does this function suspend" to be a particularly interesting effect for a function to have to commit to and the fact that it poisons the entire callstack makes it very difficult to work with in practice.

Re: Ruby methods are colorless

#192
> Even more onerous, if it isn’t built into your language core like JavaScript/node.js, adding it later means modifying your entire runtime, libraries and codebases to understand it.

Interestingly, while this has proven true of async/await for many languages it has not at all been true for perl.

The pluggable keywords feature lets us register 'async' and 'await' with the parser as (block scoped) imported keywords and with a little suspend/resume trickery you get https://p3rl.org/Future::AsyncAwait which I've been using happily pretty much since it was released (generally operating on https://p3rl.org/IO::Async::Future and https://p3rl.org/Mojo::Promise objects, often both in the smae process).

I even wrote https://p3rl.org/PerlX::AsyncAwait as a pure perl proof of concept later on, which injects computed gotos as resume points ala the switch/case trick you can use for resumable functions in C (nobody should really be using that one, mind, I wrote it to prove that I could and as potential fodder for https://p3rl.org/App::FatPacker usage later).

I do very much appreciate there are a lot of reasons one might dislike perl (I've been writing it long enough my list is probably longer than most naysayers') but its sheer malleability as a language remains unusually good.

Re: Ruby methods are colorless

#193
post #164

Earlier quoted context omitted.

Now handle the following that is painlessly solved by runtimes with structured concurrency: If A failed, the whole function is failed, and we don't need B any more. To save resources we should cancel B. And vice versa, cancel A if B failed.

import github.com/carlmjohnson/flowmatic func whatever(ctx context.Context) { err := flowmatic.Race(ctx, taskA, taskB) } Provide your definition of taskA and taskB, of course. As I said in another message, this is not a particularly fruitful line of attack in either direction. All the languages in question are perfectly capable of abstractions.

I don't like that the return values of the tasks has to be communicated with side effects, but I'll concede that it's quite painless.

I guess I'm just still salty when someone commented (in another post a long time ago) that golang only has `go` (compared to `launch`, `async`, and `coroutineScope` in Kotlin) and is simpler.

> All the languages in question are perfectly capable of abstractions.

I don't think async functions in JS can be cancelled though.

Re: Ruby methods are colorless

#195
post #175

Kotlin solved this pointless debate long time ago the moment they’ve released coroutines. Best of both worlds: you no longer have two functions with ReturnType and Promise . You just mark potentially blocking function with suspend and you’re done.

I don’t see how. Only suspending functions can call other suspending functions. You still end up having to mark your call stack all the way up.

runBlocking {}

Re: Ruby methods are colorless

#196
post #51

Earlier quoted context omitted.

Honestly, despite that blog, async coloring is a feature. The pattern enforces implicit critical sections between yields and the coloring is how the dev can know what will yield.

For some reason requiring the programmer to use additional syntax at the call site to mark behavioural properties of called functions is not a popular language feature generally. I guess eg TypeScript could add it as a user extensible feature. Would it be useful to be able to require things like this in your internal API? let gizmos = nocheckperms lookupRequestedGizmos(request);

You're trading complexity for expressiveness but the await keyword syntax is essentially unwrap sugar. Dereferencing a pointer is similar syntax.

It's possible to write a language where awaiting a task is done through a method on the task type. I don't think this is ideal because the whole reason you're using explicit yield points is so you can tell when something yields. Using method syntax makes that harder to see at a glance.

Re: Ruby methods are colorless

#197
post #58

Earlier quoted context omitted.

TLDR; I hadn't meant it that way, but in web pages it really is enough. Web pages generally don't have computation time to worry about, mostly just IO. This simplifies scheduling because whatever is coordinating the event loop in the browser (or other UI) can just background any amount of independent IO tasks. If there is computation screwing with share mutable state something with internal knowledge needs to be invo…

It doesn't sound to me like the engines you dealt with use ECS, which are usually resolved with a job system (your work units and functors), but correct me if I'm wrong. The good job systems I've dealt with have their dependencies in the functors. So you "wait" on a job to finish, which is really a while loop that plucks and executes other jobs while the dependency job hasn't finished. This kind of job system is nice…

The ECS concerns don't really relate to threading concerns.

I have worked with and without ECS systems both with and without good threading models. ECS writes do create possible issues if write-locks need to be acquired but that isn't usually so big of a deal.

Re: Ruby methods are colorless

#198

Earlier quoted context omitted.

> The main problem is that someone got it in their head This unnecessarily trivializes the technical problems at hand. This wasn't just something someone got in their head, especially considering... > 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. This is exactly what JavaScript did. The program only yields at `await`e…

> This unnecessarily trivializes the technical problems at hand. Making a language that automatically generates two versions of a function, one that is async and returns a Promise-wrapped object, and another that is sync, is not hard. > This is exactly what JavaScript did. No, it isn't. JavaScript requires you to declare functions as async at the function definition , and you can't call async functions from sync ones…

If it wasn't hard, it would have been done. I suppose we should all await your backwards compatible proposal?

> No, it isn't.

Yes, actually, it is. Async functions are a concept that only affects the internal structure of a function - to generate the state machine that allows yielding at `await` keywords and resuming after they resolve. Externally they are no different from "sync" Promise-returning functions.

So they only thing that async functions do is enable yielding at the callsite, the `await` keyword is what actually yields at the callsite and you can await anything, not just async functions.

Again:

> 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.

This is what `await` is - `await` yields. Non-await calls don't yield.

Re: Ruby methods are colorless

#199

Earlier quoted context omitted.

> The main problem is that someone got it in their head This unnecessarily trivializes the technical problems at hand. This wasn't just something someone got in their head, especially considering... > 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. This is exactly what JavaScript did. The program only yields at `await`e…

> This unnecessarily trivializes the technical problems at hand. Making a language that automatically generates two versions of a function, one that is async and returns a Promise-wrapped object, and another that is sync, is not hard. > This is exactly what JavaScript did. No, it isn't. JavaScript requires you to declare functions as async at the function definition , and you can't call async functions from sync ones…

[deleted]

Re: Ruby methods are colorless

#200

Earlier 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.

> … Erlang … inspired by the message passing semantics of Smalltalk.

What makes you think that?

Post reply on HN