HackerTrans
TopNewTrendsCommentsPastAskShowJobs

tomck

no profile record

comments

tomck
·há 9 meses·discuss
> `if (file_exists(f))` is misuse of the interface, a lesson in interface design, and a faulty pattern that's easy to repeat with async-await.

It's even easier to repeat without async-await, where you don't need to tag the function call with `await`!

> Think about it, you can't `await` on part of the state only once and then know it's available in other parts of code to avoid async pollution. When you solve this problem, you realize `await` was just in the way and is completely useless and code looks exactly like a callback or any other more primitive mechanism.

I don't understand why you can't do this by just bypassing the async/await mechanism when you're sure that the data is already loaded

```

data = null

async function getDataOrWait() { await data_is_non_null(); // however you do this return data }

function getData() { if (data == null) { throw new Error('data not available yet'); } return data; }

```

You aren't forced into using async/await everywhere all the time. this sounds like 'a misuse of the interface, a lesson in interface design', etc

> I think "how to express concurrency" is a question I'm not even trying to answer

You can't criticise async/await, which is explicitly a way to express concurrency, if you don't even care to answer the question - you're just complaining about a solution that solves a problem that you clearly don't have (if you don't need to express concurrency, then you don't need async/await, correct!)

> point to approaches that completely eliminate pollution and force you to write code in that "unrolled" way from start, something like Rx or FRP where time is exactly the unit they're dealing with.

So they don't 'eliminate pollution', they just pollute everything by default all the time (???)
tomck
·há 9 meses·discuss
> I replied directly to you

My comment was responding only to the person who equated threads and async. My comment only said that async and threading are completely orthogonal, even though they are often conflated

> `is_something_true` is very simple, if condition is true, and then inside the block, if you were to check again it can be false, something that can't happen in synchronous code

It can happen in synchronous code, but even if it couldn't - why is async/await the problem here? what is your alternative to async/await to express concurrency?

Here are the ways it can happen:

1. it can happen with fibers, coroutines, threads, callbacks, promises, any other expression of concurrency (parallel or not!). I don't understand why async/await specifically is to blame here.

2. Even without concurrency, you can mutate state to make the value of is_something_true() change.

3. is_something_true might be a blocking call to some OS resource, file, etc - e.g. the classic `if (file_exists(f)) open(f)` bug.

I am neutral on async/await, but your example isn't a very good argument against it

Seemingly nobody ever has any good arguments against it

> async-await pollutes the code completely if you're not strict about its usage

This is a good thing, if a function is async then it does something that won't complete after the function call. I don't understand this argument about 'coloured functions' polluting code. if a function at the bottom of your callstack needs to do something and wait on it, then you need to wait on it for all functions above.

If the alternative is just 'spin up an OS thread' or 'spin up a fiber' so that the function at the bottom of the callstack can block - that's exactly the same as before, you're just lying to yourself about your code. Guess what - you can achieve the same thing by putting 'await' before every function call

Perhaps you have convinced me that async/await is great after all!
tomck
·há 9 meses·discuss
I think you replied to the wrong person.

That being said, I don't understand your `is_something_true` example.

> It's very often used to do 1 thing at a time when N things could be done instead

That's true, but I don't think e.g. fibres fare any better here. I would say that expressing that type of parallel execution is much more convenient with async/await and Promise.all() or whatever alternative, compared to e.g. raw promises or fibres.
tomck
·há 9 meses·discuss
> I do fully understand people who can't get their heads around threads and prefer async

This is a bizarre remark

Async/await isn't "for when you can't get your head around threads", it's a completely orthogonal concept

Case in point: javascript has async/await, but everything is singlethreaded, there is no parallelism

Async/await is basically just coroutines/generators underneath.

Phrasing async as 'for people who can't get their heads around threads' makes it sound like you're just insecure that you never learned how async works yet, and instead of just sitting down + learning it you would rather compensate

Async is probably a more complex model than threads/fibers for expressing concurrency. It's fine to say that, it's fine to not have learned it if that works for you, but it's silly to put one above the other as if understanding threads makes async/await irrelevant

> The stdlib isn't too bad but last time I checked a lot of crates.io is filled with async functions for stuff that doesn't actually block

Can you provide an example? I haven't found that to be the case last time I used rust, but I don't use rust a great deal anymore
tomck
·há 9 meses·discuss
I have tried a model on my laptop+GPU before, and it is incredibly unusable. Incredibly slow and just bad output for exactly the work you describe

If you're looking for a cheap practical tool + don't care if it's not local, deepseek's non-reasoning model via openrouter is the most cost efficient by far for the work you describe.

I put 10 dollars in my account about 6 months ago and still haven't gotten through it, after heavy use semi regularly.
tomck
·há 10 meses·discuss
This isn't what people are talking about, you aren't understanding the problem

With RAII you need to leave everything in an initialized state unless you are being very very careful - which is why MaybeUninit is always surrounded by unsafe

    {
        Foo f;
    }

f must be initialized here, it cannot be left uninitialized

    std::vector<T> my_vector(10000);
EVERY element in my_vector must be initialized here, they cannot be left uninitialized, there is no workaround

Even if I just want a std::vector<uint8_t> to use as a buffer, I can't - I need to manually malloc with `(uint8_t)malloc(sizeof(uint8_t)*10000)` and fill that

So what if the API I'm providing needs a std::vector? well, I guess i'm eating the cost of initializing 10000 objects, pull them into cache + thrash them out just to do it all again when I memcpy into it

This is just one example of many

another one:

with raii you need copy construction, operator=, move construction, move operator=. If you have a generic T, then using `=` on T might allocate a huge amount of memory, free a huge amount of memory, or none of the above. in c++ it could execute arbitrary code

If you haven't actually used a language without RAII for an extended period of time then you just shouldn't bother commenting. RAII very clearly has its downsides, you should be able to at least reason about the tradeoffs without assuming your terrible strawman argument represents the other side of the coin accurately
tomck
·há 10 meses·discuss
This whole page, and their response in this thread, is about tigerbeetle as a transaction processing database - e.g. financial transaction processing

I think this is very clear, I don't know why you're saying that tigerbeetle is trying to make a generic claim about general workloads

The comment you're replying to explicitly states that this isn't true for general workloads