5 ms·
I really don’t agree with the idea that this is functional colouring. Then we have to start talking about function colouring in a whole bunch of new contexts li
by audunw 1y ago
I really don’t agree with the idea that this is functional colouring. Then we have to start talking about function colouring in a whole bunch of new contexts like with Zigs explicit passing of allocator. Or any other parameter that needs to be explicitly passed to use some kind of interface.
I think we should stick to talking about colouring when there is special calling conventions or syntax, which has the consequence of having to write separate libraries/modules for async code and non-async code.
That is the significant problem we have been seeing with many async implementation, and the one which Zig apparently fully solves.
- dwattttt 1y ago> Then we have to start talking about function colouring in a whole bunch of new contexts like with Zigs explicit passing of allocator. That's pretty much where we are though. If you have a function that isn't passed an allocator, and now it needs to call a function that does take an allocator, we're in the same place. Rust's 'async' keyword changes the type of the return value, but you can just write the different return value yourself; it's 'coloured' purely by what it means to be returning a 'Future'.
- koolala 1y agoSo its impossible to get an allocator through a different means from inside a function? It must be passed in?
- dwattttt 1y agoNo, it's entirely possible. And that's why we don't think about "has an allocator" as a colouring problem. Likewise if JavaScript had an easy way to get a handle to its Runtime, and a function "block on promise" in its early days, we'd have never had all these "colouring" arguments.
- Dylan16807 1y agoIf javascript worked differently we wouldn't have arguments about that significant feature of javascript. How would you add "block on promise"? Javascript started off without the ability to block on anything, not even I/O because it didn't have I/O. Later when XMLHttpRequeest was added it was purely callback-based. There are ways to make that API work but introducing the concept of blocking would be a big language change. It's not fixing a flaw, it's trading away some complications for a different pile of complications. There's still a conflict to resolve in language design when you want some functions that are synchronous and don't block and other functions that are asynchronous. Edit: I guess javascript blocks on alert() but that doesn't seem like what you'd want "block on promise" to do...
- dwattttt 1y agoJavaScript is (notionally) "single threaded", you can block with just a busy loop; that's not a language change. It's bad design to block, which I expect is what you mean, but that's not a language problem. If you did so in a Worker, you'd have your "don't block the UI thread" in there too.
- Dylan16807 1y agoIf you busy loop waiting for something in javascript, your program dies. They're not just a bad idea, they're a non-option. Blocking in the sense of blocking I/O or blocking on a system call is not possible in javascript. So again I ask what you have in mind for a "block on promise" call. The ideas that come to my mind all require significant redesigns of the execution model, or copping out by making every function async and treating it like an await. In particular with workers in mind, I'll put it this way: If you don't allow "block on promise" in the main thread, you generally avoid these issues, but you also don't solve the problem, you still have async versus not async causing many headaches. If you do allow it on the main thread, how do you keep your page functioning? I can imagine resolutions but they all have severe compromises.
- dwattttt 1y agoEvery time you call a JS function, it's blocking; if it internally busy-looped, you'll die just as much as if you do the loop yourself. Being able to block on an async function call is just as much of a risk; if it returns quick, you live, if it returns slow, you die. The solution to "main page unresponsive, terminate page?" is to always return promptly to the Runtime, so e.g. make everything async. But JavaScript is a language, and it doesn't just exist on web page main threads. As much as JS's proliferation everywhere else isn't my cup of tea, a blocking call in a JS cli tool is what you want. EDIT: I guess to be explicit: > So again I ask what you have in mind for a "block on promise" call I expect it to have the same guarantees and risks of calling a non-async JS function.
- woodruffw 1y agoThis is effectively a special calling convention: Zig expects you to pass in a "token" object that communicates a kind of effect (I/O in this case). No token, no effect (modulo a soundness hole). This is not a new pattern, and I think it's a pretty good one (and is arguably more ergonomic and general than syntax-level effects). But it's quintessential function coloring.
- throwawaymaths 1y ago> Zig expects you to pass It does no such thing. you could pass a function a vtable and the vtable could have one implementation that calls an io stashed in the parent of the vtable, and a different vtable that doesnt and the function calling the vtable would be none the wiser. what is the color of the function that took the vtable? this is not just academic; it would be for example the basis for mocked integration tests on a database or over the net api call.
- woodruffw 1y agoThat's a calling convention, with indirection. You need some kind of capability token for this kind of asynchronicity scheme; it doesn't matter how you get it, but it needs to be there. To be clear, there's nothing wrong with this; it's just another way to encode capabilities/effects. > what is the color of the function that took the vtable? It has the I/O effect.
- throwawaymaths 1y ago> It has the I/O effect it does not, because it can take a vtable that does not call i/o concretely: const VTable = struct { f: &fn (*VTable) void, }; const A = struct { io: IO, v: VTable = .{ .f = &A.uses_io }, fn uses_io(this: *VTable) void { const self: *A = @fieldParentPtr(.v, this); self.io.some_io_fn(...); } }; const B = struct{v: VTable = .{.f = &void_fn}}; fn void_fn(_: *VTable) void {} \\ WHAT IS THE COLOR OF THIS FUNCTION? pub fn calls_vtable(v: VTable) { v.f() }
- hamandcheese 1y ago> which has the consequence of having to write separate libraries/modules for async code and non-async code. That is not a consequence of function coloring or syntax, it is a consequence of having multiple ways of performing IO.