Live data from Hacker News

What color is your function? (2015)

journal.stuffwithstuff.com

181–190 of 198 posts

Re: What color is your function? (2015)

#181
post #10

I wish the key word was instead dontawait and was used inversely to how await is used. 99% of the time I'm using an async function, despite however slow it is, there's nothing for my code to do but wait for it to finish. But if for some reason I would like the next line of code to run before the current one is done, I'll let you know . Like, why can't my sync function await something asynchronous? If it has to lock u…

> Like, why can't my sync function await something asynchronous? The answer, at least for Python, is that it is an intentional limitation because the alternatives introduce some quite bad trade-offs. Option 1: your awaited promise goes into the main async event loop. This is bad because it means that your single-threaded sync function now needs to be thread-safe, and so does any sync code that calls your sync functio…

Option 1 could be easily solved by having an atomic {} blocks that statically error if call any potentially async function in it. This is better as it document where an externally visible invariant is temporarily broken (i.e. reentrancy is required), instead of being implied by the code and potentially being broken a a future code change.

Implicit thread safety across async blocks of course break if you introduce actual shared multithreading in the language, while if you have atomic blocks at least you can build transactional memory on top.

Re: What color is your function? (2015)

#182
post #10

I wish the key word was instead dontawait and was used inversely to how await is used. 99% of the time I'm using an async function, despite however slow it is, there's nothing for my code to do but wait for it to finish. But if for some reason I would like the next line of code to run before the current one is done, I'll let you know . Like, why can't my sync function await something asynchronous? If it has to lock u…

This is so true. In webgpu, the functions to request a GPU device / GPU adapter are both async, and I often wonder, what is my engine going to do in the few milliseconds before it's grabbed a handle to the GPU? It can't render anything, it can't load anything... If I really had to guess I would think it's so that when compiled for web, the page doesn't lock up when the browser is showing the "allow this site to acces…

I know approximately zero about webgpu, but I assume it allows for pipelining.

Re: What color is your function? (2015)

#183
post #10

I wish the key word was instead dontawait and was used inversely to how await is used. 99% of the time I'm using an async function, despite however slow it is, there's nothing for my code to do but wait for it to finish. But if for some reason I would like the next line of code to run before the current one is done, I'll let you know . Like, why can't my sync function await something asynchronous? If it has to lock u…

Julia does this – you generally write synchronous, single-threaded functions most of the time, and can use code like `t = @spawn foo(b)` to get a Task, and then `output = fetch(t)` to wait for it and get the value. I like this general approach a lot, it's overall quite nice for Julia's core use case of number crunching, it means you typically make decisions around concurrency at the call sites. Though it does rely he…

See also Cilk/Cilk++

Re: What color is your function? (2015)

#184

I think a few things are simultaneously true here: 1. async/await is a huge improvement over callbacks. 2. doing asynchronous programming through callbacks has always been a messy hack, primarily coming from languages that couldn't/wouldn't do real concurrency in their runtimes and async/await just papers over it without fixing the fundamental problems 3. threads are a lot more elegant from a language design standpoi…

definitely point 1.

Also: 5. Async/await is a necessarily evil that allows for extremely high concurrency (10s of millions of concurrent tasks) where stackful coroutines and threads wouldn't practically scale.

Re: What color is your function? (2015)

#185
post #124

Earlier quoted context omitted.

Something I have been thinking about recently is this: metaphors are often a way that authors use to make an argument in a way that is more engaging than: here is fact A, here is fact B, etc. But some metaphors are so strong that they make a stronger argument than the actual facts! And when you hear an argument with such a strong metaphor, you can often end up feeling very convinced of a particular point, even though…

I do find it annoying. Let's say in JS I have `result = list.map(f)` but now `f` returns a Promise. `result = await Promise.all(list.map(f))` is less pleasant to read. And before writing it, I have to think if I want the `f` function to execute concurrently across all entries of the list, or one at a time: `for (const elem of list) { await f2(elem) }`. Or maybe I should use a library like `p-map` and carefully set th…

But these are all legitimate choices you have to make, each with their own tradeoffs. Fire-and-forget, all in parallel, and batch are all different - you might end up selecting any based on the characteristics of the work you have to do.

Re: What color is your function? (2015)

#186
post #139
post #92

Earlier quoted context omitted.

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

> you'll probably return your own VisionResult (extends Object) unless it throws your TooCloudedException (extends Exception). > When someone else writes a wrapper or higher-level layer that uses your code, then it'll be up to them to convert or wrap those results and exceptions into something suitable for their level of abstraction. Why though? What do you gain other than longer stacktraces with all those wrappers?…

> Why though?

I'm not sure if this means:

1. "Why bother throwing a new exception of a different class, and not bubble up the original as-is?"

2. "Why would you use the standard feature of all Java exceptions which allows you to chain them, and not just throw away the original exception after copying some of its message string?"

For #1, it should be obvious in almost any language, if not instinctive: The library for managing customer records should return `Customer` objects instead `some.database.FetchResult` ones, and likewise it should throw `CustomerAccessException` instead of a `some.database.DatabaseException`. It's a matter of abstraction and preventing weird coupling.

For #2, surely you've been debugging something before and cursed at how the log is missing crucial details that could have saved you hours of trying to reproduce the problem? By chaining exceptions, you get automatic access the inner exception type, message string, additional properties, and deeper stack trace.

* Discarding the 'cause' at this point is a waste, the work was already done, the memory already allocated, why not benefit from it?

* Sometimes it's not your bug, and having the inner exception makes it much easier to get the necessary cooperation of someone else and get it fixed faster.

* Since the declared type is Throwable, it's not creating a compile-time dependency between layers. You could do a softer runtime test on the cause's type, but usually that's a temporary workaround while you complain that someone else's code is hiding critical details.

> there really aren't that many different kinds of error

I feel that's naive, handling edge cases and errors becomes more important as any system gets larger. Some are emergent from the complexity, others always existed but we can't afford to ignore them anymore.

There are many errors because all errors are contextual! Bad-input in the HTML form-submit is not the same as bad-input in the SQL query. A failed invariant of a tree that somehow made a loop is not the same as a failed invariant of something reporting negative length. An SSH handshake error is not a TLS handshake error.

Re: What color is your function? (2015)

#188

Earlier quoted context omitted.

It's an interesting repeat submission to study how HN comments change over time though. Regarding content, I agree with you. Async/Await is an amazing paradigm in JS for simplifying callback patterns and non-blocking suspense. In other programming languages, there exist other intriguing paradigms that are more elegant and emphasize other aspects of "async"; my prime example 2 would be Erlang, but I am not experienced…

While non-trivial in several ways, there are standard Web APIs such as Web Workers, Web Audio API, OffscreenCanvas, SharedArrayBuffer, etc. which help to construct modern, multi-threaded applications in JavaScript. Hopefully today, any experienced JavaScript-focused web developer should be experienced with more async paradigms than just async/await. I think these APIs address real issues, but it also makes the entire…

Yes, my horizon is not quite that limited, but in fact I mostly get to use these capabilities you mention in hobby projects, apart from a few exceptions, given the stack I currently work on for a living. I had Worker threads in mind when I wrote the comment but considered it a disgression.

Didn't want to say that JS cannot provide other paradigms for asynchronous code apart from the async function syntax and Promises.

Re: What color is your function? (2015)

#189

Earlier quoted context omitted.

That's more a consequence of Rust needing its tagged unions declared up front so it can lay them out consistently in memory without runtime type information. Python and TypeScript have untagged unions (that are discriminated at runtime by the RTTI attached to all objects in the underlying dynamic language); they don't happen to have an equivalent of Rust's ? operator, but if they did it'd work like you're describing.

"untagged union" usually means "no discriminant" not "runtime discriminant." (Rust has both tagged (enum) and untagged (union) unions, but untagged ones are unsafe and therefore mostly used for C interop and similar cases.)

People often call Python/TypeScript unions "untagged unions" even though they're a very different creature from C/Rust unions. Ideally there'd be a term specifically for them but I'm not aware of one.

Re: What color is your function? (2015)

#190
post #29

Earlier quoted context omitted.

That's mostly because BEAM uses an actor-style approach while predating the concept of actors, isn't it? Interesting artefact of history if so Edit: upon rechecking, apparently that's not exactly right, and Erlang designers learned of actors after designing the language, which makes it all the more interesting

I've spent the last decade in erlang / elixir / OTP. I think a lot of the naming comes from the early use of erlang as effectively an "OS" for telecom switches. I always joke that BEAM wants to be the operating system.

> I've spent the last decade in erlang / elixir / OTP.

Do you have a blog? I would love a peek into your unique experience.

Post reply on HN