10 ms·
This is interesting, it seems like a global mode that kind of turns normal Zig code into Go or Erlang-like non-blocking code. It does mean you have to hold non-
by jolux 5y ago
This is interesting, it seems like a global mode that kind of turns normal Zig code into Go or Erlang-like non-blocking code. It does mean you have to hold non-local context in your head while reading functions, but maybe that's a worthy tradeoff?
- messe 5y ago> This is interesting, it seems like a global mode that kind of turns normal Zig code into Go or Erlang-like non-blocking code Nope! There's no language magic going on, and the global switch is just a global variable in the root module. It only affects a few functions in the standard library that check that variable. Zig relies heavily on compile time code executing for metaprogramming, and your code can read symbols from the root source file via @import("root"). All that pub const io_mode = .evented; does is set a variable that the standard library then checks. When io_mode is set to .evented, the library sets up an event loop and makes async calls internally. When it isn't, it makes blocking calls as you would expect. Unless you explicitly use 'async' to call functions, then they're going to act as if they block as they will be immediately await-ed upon, so there's no change.
- jolux 5y ago> Nope! There's no language magic going on, and the global switch is just a global variable in the root module. It only affects a few functions in the standard library that check that variable. I didn’t say there was magic, I was describing the practical effect of this feature. On a type-theoretic level, it’s like entering a global async monad, which is roughly the structure that Go and Erlang have. But since you mentioned it, global variables that have side effects are definitely magic, in my view. If I did this in Ruby by monkey-patching synchronous IO methods in response to a global flag, people would definitely call it magic. And I understand how the feature works, but my reservations about it remain. As for results being immediately awaited meaning there’s no change, I think I disagree. What happens if another task fails and brings down the whole system while I’m awaiting something? It wouldn’t have been scheduled in if I was programming synchronously.
- deleted 5y ago[deleted]
- meowface 5y ago>But since you mentioned it, global variables that have side effects are definitely magic, in my view. If I did this in Ruby by monkey-patching synchronous IO methods in response to a global flag, people would definitely call it magic. It definitely is "magic", but it's one of the few areas where I welcome it, personally. What other options are available? The three I know of are function-colored (JavaScript, Python), async/automatic context-switching by default (Go, Erlang), or monkeypatching to go from colored to async/automatic context-switching by default (Zig, Python gevent). I also hate globals, side effects, and monkeypatches, but I find the monkeypatch method to be the best compromise. I still use gevent in pretty much every Python project, and have for the past 10 years.
- jolux 5y agoI don't think there is really a "better" option than this. Personally I find it distasteful because (if I understand this feature correctly) it means I have to know whether somebody turned on the async flag in another file to fully understand the possible control flow of a function I'm reading. This is different from Erlang because we just assume that every line can be preempted, and different from async-await because seeing async-await means you don't know if the code is actually going to run asynchronously. It's not the choice I would have made, but I am a stickler for theoretical cohesiveness and local readability, and Zig is kind of an anti-theory language. I would have chosen function colors, in all likelihood.
- ghoward 5y ago> On a type-theoretic level, it’s like entering a global async monad, which is roughly the structure that Go and Erlang have. This is the most concise summary of what Zig actually does! Thank you. I always felt it was a little off, but it makes sense when you think about it in terms of "Zig makes all of your functions red, even if you don't want them to be." In fact, in the article linked above, it says this in the FAQ: > Q: SO I DON’T EVEN HAVE TO THINK ABOUT NORMAL FUNCTIONS VS COROUTINES IN MY LIBRARY? > No, occasionally you will have to. As an example, if you’re allowing your users to pass to your library function pointers at runtime, you will need to make sure to use the right calling convention based on whether the function is async or not. You normally don’t have to think about it because the compiler is able to do the work for you at compile-time, but that can’t happen for runtime-known values. So in essence, Zig actually is still colored, but the compiler handles for you what it can.
- hsn915 5y agoHow is that not magic? I suppose user code can do the same thing, but still, it's kind of magic. When people speak of magic in code, they mean something that looks innocent but has huge ramifications because some other part of the code (that you are not aware of) does special handling. In this case, what looks like a simple variable declaration acts more like configuration, but it doesn't look like configuration. It would be much less magical if instead the language required you to call something from main, for example: fn main() { std.setup_event_io(); .... }
- gpderetta 5y agowhat happens if there are multiple conflicting settings of io_mode (does Zig have the concept of translation unit?).