3 ms·
This 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, n
by woodruffw 1y ago
This 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() }
- woodruffw 1y agoIt also has the I/O effect. You don’t need to call or make use of an effect to be “tainted” by it; it just needs to be in the closure (or whatever scope is relevant in the language). Intuitively: if you mark a function as async, it doesn’t stop being async “colored” just because you don’t actually perform any async operations in it. This is the same thing.
- deleted 1y ago[deleted]
- throwawaymaths 1y agoyou might be talking about stackless coroutines, which are currently not part of zig, in which case, yes, the compiler might [0] have to instantiate different functions under the hood for the stackless-coro and the non-stackless-coro cases, with some mechanism to drop in an executor at the boundaries. until then its really hard to claim that the functions are colored. [0] But even in that case there's not really coloring because if you provide a single io implementation there won't be different functions, even at the compiled level.
- woodruffw 1y agoNo, I really just mean from a PLT perspective. The sync/async implementation used under the hood doesn't matter; what matters is that an `Io` in the closure is a token type for communicating effects. No instantiated or enclosed token; no effects. People seem to be really defensive about this, like it's a bad thing. It isn't! It's arguably a significantly cleaner way to handle what people confusingly call "coloring." But that doesn't make it not "coloring," because coloring is about effects and vitality, not about keywords and syntax.
- throwawaymaths 1y ago1. the original author of the function coloring post wad not exactly a theorist so if you're applying some other idea of what coloring is, then you're muddying the waters. 2. here's what i have to say about your idea of what coloring is: That's all fine and good in theory, but in practice it makes no difference, at the user level, or at the compiler level.