4 ms·
> 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
by 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.