Live data from Hacker News

What color is your function? (2015)

journal.stuffwithstuff.com

111–120 of 198 posts

Re: What color is your function? (2015)

#111
post #65

Earlier quoted context omitted.

#3 is not satisfied, as you noted in #2. You can call `throws` methods from non-`throws` methods by wrapping the call in a try catch, and `throws` methods can call non-`throws`. There isn't an exclusivity asymmetry like there is for JavaScript async.

That only applies to Javascript, which, is mostly only red functions anyways (there are no blocking apis in javascript). Javascript doesn't have the coloring problem in the way Python or Rust has it. In Python, you can wrap the call with asyncio.to_thread, in rust with tokio::spawn_blocking.

I think you got it backwards: JavaScript has the coloring problem while other languages don't.

"Red functions are more painful to call" alludes to async functions. Every await yields back to the event loop, which adds overhead. Making every function red/async adds a performance cost (and makes it harder to reason about race conditions), which is why JavaScript has a mix of blue and red functions.

Other languages can escape the "red functions can only be called by red functions" trap, like Python asyncio.run or Tokio block_on. JavaScript has no such alternative, not even in Node. Therefore, Python and Rust don't have function coloring, but JavaScript does.

Re: What color is your function? (2015)

#112
post #30

I really don't like this article. It has a catchy, profound-sounding title that people bandy about to argue against stuff they don't like. All functions, even non-async functions, are colored. In any large system codebase you'll have functions that can only be called in certain situations, with the right setup, whatever, and if you're lucky this is communicated by types but regardless those restrictions can't be avoi…

> All functions, even non-async functions, are colored.

Not by the analogy laid out in the article.

Re: What color is your function? (2015)

#113
post #30

I really don't like this article. It has a catchy, profound-sounding title that people bandy about to argue against stuff they don't like. All functions, even non-async functions, are colored. In any large system codebase you'll have functions that can only be called in certain situations, with the right setup, whatever, and if you're lucky this is communicated by types but regardless those restrictions can't be avoi…

> It's easy to call low-restriction functions from high-restriction ones and not the other way around.

do you have an example in mind when you say this? I think there's some unique messes with async/await (especially when combined with OOP and extension points... either your extension points _all_ have to be async or you have to have awkward restrictions), in a way that, say, permission checks don't have IMO.

a syntax-less "await function" that climbs up the stack trace to whoever is waiting and holds onto the suspension _is_ a way out of the problem the article describes. Requires runtime support but it effectively means you can always suspend.

Re: What color is your function? (2015)

#114

Earlier quoted context omitted.

What I like least about this article is that it's completely soured the entire context of asynchronous programming. Invariably, any time someone discusses design of an async functionality, function coloring is brought up, with almost no analysis as to how it applies and why it's a good or bad thing. (Ironically, I probably see more in-depth analysis these days as to why this article isn't apropos than why it is when…

I am so happy I have never heard anyone IRL say colored functions. It would annoy me. The concept is interesting but like all engineering it is a trade off. In Node amd Go you don't get a choice anyway. In C# you might choose based on performance thinking of thread pools etc IIRC. When programming in Node I find in practice async and "colored functions" no issue especially with async await. Except for performance iss…

> When programming in Node I find in practice async and "colored functions" no issue especially with async await. Except for performance issues they come with sometimes but not at a programming level.

JS solves this problem in two ways in the ecosystem:

- basically saying "all functions must be async" in practice

- allowing you to await a non-awaitable ("await 3" is valid)

so library authors can "force" async/await, but users don't actually have to interact with it when they don't need to. But "everything" being async/await means it's all 'basically fine' anyways

There's also the fact that JS libraries tend to be "pass in a bunch of callbacks" vs, say, Python's "override this class". It makes it much easier for libraries to have everything be async and have it really not get in the way.

Python libs tend to have much larger API surfaces due to how OOP works. So async-y internals works are harder to isolate cleanly without breaking the public API. But if you make your API "async-first" then the debugging experience in Python is miserable (try pdb'ing your way through awaitables....)

Even here though there are problems. For example, I've tried in the past to replace some lib with a more performant WASM-y thing. But it couldn't be a drop in replacement because the original library was a sync-only API, and the replacement was async!

Something very silly: you write "function add(x, y) { return x+y }". A bunch of people do things like "add(add(x, y), z)" everywhere. You find out you could make "add" "better" with async/await. You now have to get all callers to rewrite.

So what everyone does is just throw _everything_ in to the async/await pile. Which... I guess is fine but I personally dislike writing "await add(await add(x,y)), z)".

(aside: Rust's postfix await at least makes this kinda refactor less annoying)

Re: What color is your function? (2015)

#116

Earlier quoted context omitted.

I'm fairly sure the author was making reference to the famous article What Color Are Your Bits? https://ansuz.sooke.bc.ca/entry/23 which is even more abstract, because some large numbers are coloured "legal" and the same large numbers are coloured "illegal", based on where you got the numbers from . All functions are not coloured, don't try to wriggle out of it by generalising. This article is a specific complaint ab…

Agreed. Every time this article makes the rounds, people get hung up on the syntax, and not the performance considerations discussed towards the end. Nystrom wrote a whole book on interpreters, and his main criticism here is the big mess of chained closures this makes at runtime, compared with pausing/resuming green threads.

[deleted]

Re: What color is your function? (2015)

#117
post #92

Earlier quoted context omitted.

The problem with Java's checked exceptions is that it has too many kinds of exceptions to choose from and they're overly specific. Compare with Go, which has a single error interface and had it from the beginning, so it's used everywhere. Returning a new kind of error is always a local change, unless it's a function that didn't previously report errors at all. Type systems permit either standardization or fragmentati…

> too many kinds of exceptions to choose from I don't understand, why would you need to pick a checked exception? It's the dual or mirror of feeling paralyzed over a return-type because there are "too many kinds of Object to choose from." If you're writing a CrystalBall class with a gaze_deeply() method, you'll probably return your own VisionResult (extends Object) unless it throws your TooCloudedException (extends E…

This isn't like returning Object. It's more like returning a String. After using a language with a common String type, who wants to go back to writing code to convert between between different kinds of strings? Having to choose among different string implementations because there's no standard usually leads to boilerplate code doing conversions at the borders.

Usually you just want to propagate or log errors, so having a generic error interface is sufficient. It's true that in Java, you can wrap exceptions, but that's extra boilerplate.

(And yes, Go does notoriously have error propagation boilerplate that they should fix, but that isn't a type system problem.)

Re: What color is your function? (2015)

#118

Earlier quoted context omitted.

The functions are still coloured, just implicitly. IYKYK to spawn a goroutine or not ts.

> The functions are still coloured, just implicitly. IYKYK to spawn a goroutine or not ts. In Go, you can choose to either block on a function call or to execute it as a go routine. The function has no "color" in the sense of the article. If you want to print asynchronously, you can with a `go fmt.Println("Hello")`, or you can block on that print and remove the `go `. There is no color to any function. And the functi…

Say you have a function like validate_user(). In Go, should you block the main thread on this call, or fork and join? What if it makes a DB request and now your UI is blocked for 2 seconds or something? You need to know implicitly you need to call validate_user() in a goroutine, and then deal with forking and joining manually. If it's explicitly coloured as async, you know.

In most async/await languages you can run async functions as sync, eg. Tokio's block_on method or C#'s .Result.

Re: What color is your function? (2015)

#119
post #30

I really don't like this article. It has a catchy, profound-sounding title that people bandy about to argue against stuff they don't like. All functions, even non-async functions, are colored. In any large system codebase you'll have functions that can only be called in certain situations, with the right setup, whatever, and if you're lucky this is communicated by types but regardless those restrictions can't be avoi…

What I like least about this article is that it's completely soured the entire context of asynchronous programming. Invariably, any time someone discusses design of an async functionality, function coloring is brought up, with almost no analysis as to how it applies and why it's a good or bad thing. (Ironically, I probably see more in-depth analysis these days as to why this article isn't apropos than why it is when…

The problem with function color exists when you can't abstract over it[1]

Some statically typed languages (I believe both Haskell, ocaml) have powerful type system that allow abstracting over function types and function colors. Color is not an issue here.

Some other statically typed languages (C#, rust, and C++ (at least with the built-in stackless coroutines)) can abstract over types but not over colors. This is a problem.

Some statically typed languages (Go) do not encode async-ness statically, so it is not an issue[2].

Some dynamically typed languages (scheme, Lua, lisp) also do not encode async-ness statically. Everything is fine.

Finally there are some dynamically typed languages (python, js) that, eskew static types but for some reason still decide to encode async-ness statically. For me this is the most bizarre decision, especially as some of the justifications for static async-ness (performance, memory usage) are less relevant.

[1] for example, a litmus test is being able to implement an higher order function that inherits its color from one of its parameters. Essentially this is the problem of generically turning an internal iterator to an external one.

[2] fundamentally in these languages continuations are first class values that can be passed around, so the asyncness is naturally not bound to the function that created a continuation.

Edit: you can in principle abstract away color in any async language by simply assuming that any function call is async and await it. Then sync functions can trivially be made async. But at this point async annotations no longer convey any useful property: the language might as well implicitly await any function and require call-site annotations for diverging control flow or reentrancy requirements. More practically as languages with async evolve and grow asyncness becomes pervasive and pushes away any sync component.

Re: What color is your function? (2015)

#120

Earlier quoted context omitted.

Ok, sorry it's been about 20 years since I last javad IIRC you didn't have to declare exceptions in your function signatures. However, wrapping in try/catch seems to violate #3. Try catch is not a heavy lift of a seam between red and blue To be fair, #3 seems to have shades of grey. In some pls, you can call an async function from a sync one by wrapping it in a whole damn event loop system. Should that count?

Your question just kicks the can down the road. The problem with the article, to me, is the author doesn't want to accept a certain amount of complexity and has erected arbitrary road blocks. To you, a "whole damn event loop system" is too high a price to pay, but try/catch is not. The complexity of exceptions is invisible to you. However there are certain environments (e.g. FFI) where I dont want "the whole damn exc…

i mean no? the coloring problem appears to be solvable in zig. i maintain an FFI binding library for the BEAM vm, where once zig finishes its stackless coroutine support, the same zig function written once should be fully interchangeable between non-async, threaded-async, or async-with-yieldpoints-wrapped-in-the-BEAM's-scheduler.
Post reply on HN