Hacker News new | ask | show | jobs
by omnicognate 1022 days ago
Always with the blooming red and blue functions. You can say exactly the same thing about const.

The fact that a function can perform asynchronous operations matters to me and I want it reflected in the type system. I want to design my system on such a way that the asynchronous parts are kept where they belong, and I want the type system's help in doing that. "May perform asynchronous operations" is a property a calling function inherits from its callee and it is correctly modelled as such. I don't want to call functions that I don't know this about.

Now you can make an argument that you don't want to design your code this way and that's great if you have another way to think about it all that leads to code that can be maintained and reasoned about equally well (or more so). But calling the classes of functions red and blue and pretending the distinction has no more meaning than that is not such an argument. It's empty nonsense.

"We" don't all agree on this.

4 comments

> The fact that a function can perform asynchronous operations matters to me and I want it reflected in the type system.

async doesn't tell you whether the function performs asynchronous operations, despite the name. async is an implementation detail about how the function must be invoked.

As TFA correctly points out, there's nothing stopping you from calling a blocking function inside a future, and blocking the whole runtime thread.

I didn't say it tells me whether the function does perform such operations, I said it tells me it can. More importantly it tells me which functions (most) can't.
It would be swell if functions could be generic over this capability at compile time, so that you could get the same guarantees from the type system without implementing the same protocols more than one time.
Haskell supports this, but right from the start Rust was always wary of trying to add higher kinded types, which are necessary to support this.
As a Zig programmer I also get to enjoy this, but from the angle of language implementors not caring about type theory
Keyword generics!
Maybe a better example is returning errors, than const.

Either way, all of these changes are really annoying to make. We want less of these annoyances, not more.

We do not want functions that take floating point arguments, only u32 should be used. And don't get me started on more than one argument!
you can convert a float to a u32.

you cannot convert an function that calls async code into a sync function.

An async function is some syntactic sugar around a sync function that returns a future. You can merrily call one from the other.

You can only convert an int to a float with significant caveats. It's not a general trivial conversion. More complicated types may not be convertible at all or behave in all sorts of exciting ways (including having arbitrary side effects).

The point is that none of that is different to async functions. Of course you have to know what to do with them for them to be useful, but there is no requirement for them to "infect" calling code.

You can call .Wait on the Task it returns :)
Right, but now you are forced to convert the calling function to async.

u32 / float does not have the problem. It does not "bubble up", unless you want it to.

no, .Wait in C# or block_on in Rust keep the caller sync while evaluating the async callee, preventing the "bubble up".