6 ms·
I'm confused by "No hidden control flow" To me control flow is "if", "switch", "?:", etc. What article describes are abstractions. Abstractions are not bad. Th
by adontz 3y ago
I'm confused by "No hidden control flow"
To me control flow is "if", "switch", "?:", etc. What article describes are abstractions. Abstractions are not bad. They, just like anything else, can be abused. Maybe one may argue are easy to abuse or tend to be abused. But "Zig has no abstractions" is hardly a selling point.
On the other hard there are statements like "defer" and "try" which actually are very hidden and unusual control flow statements. Why the naming? Who the hell knows. I see try, I look for catch/except/finally, but there are none. Try in Zig means something else. "defer" is literally "try/finally", but less explicit about the scope.
"A Portable Language for Libraries"
"A Package Manager and Build System for Existing Projects"
"drop-in GCC/Clang command line compatibility with zig cc"
Is it still so after ditching LLVM?
- sapiogram 3y ago> To me control flow is "if", "switch", "?:", etc. What article describes are abstractions. Thank you for articulating this, I also don't understand why the author puts operator overloading in the same bucket as exceptions and `defer()`. Yes, `+` might call a function, but it will never affect the control flow of the parent function. Not more than a regular function call, at least.
- PH95VuimJjqBqy 3y agosee my response here: https://news.ycombinator.com/item?id=39092430 https://news.ycombinator.com/item?id=39092430
- kweingar 3y agoI think you have a different interpretation of “hidden” than Andy. He is talking about control flow that is not visible to the programmer at all. In Zig, you can understand the control flow of a particular code snippet just by learning Zig. In some other languages, operator overloading means that when you are reading unfamiliar code, you can never be sure what functions might be called.
- adontz 3y ago>> operator overloading means that when you are reading unfamiliar code, you can never be sure what functions might be called. This just means abstraction were abused. Which as I said, they can be. Nevertheless most popular programming languages (C++, C#, Python, Java, etc.) have overloaded operators, you can write "hello " + "world" (or equivalent) in any of these languages.
- defen 3y agoWhere does the memory for the combined string come from? Even if Zig had operator overloading it's not clear how a runtime `string1 + string2` could work.
- adontz 3y agoSomething like this would do https://en.cppreference.com/w/cpp/named_req/Allocator https://en.cppreference.com/w/cpp/named_req/Allocator
- defen 3y agoIn practice what would the actual code look like (pseudo-code is fine). How would I concatenate strings at runtime using `+`, once with one allocator and then again with another allocator?
- adontz 3y ago>> once with one allocator and then again with another allocator? I would: 1. Prohibit concatenating strings with different allocators. Strings with the same allocator can be concatenated. 2. Provide StringBuilder for concatenating anything in an effective manner. It's not only about different allocators, but supporting C-style strings and reducing number of allocations. So '+' is only for strings with same allocator, same UTF encoding, same everything. I'm really not fond of implicit type conversions.
- xigoi 3y ago
- mtlynch 3y agoIt means that control flow is determined by the code you're looking at. "if" and "switch" determine control flow, but you can see the control flow when you're reading that code. In languages like C++ and Java, if you have a sequence like: foo(); bar(); whether execution continues to bar() after foo() returns depends on the implementation of foo(), which you can't infer from the callsite. If foo() throws an exception, bar() won't execute. In Zig, the compiler forces you to handle exceptions (errors) at the callsite, so you can see from looking at function calls at the callsite what the potential control flow looks like. If you saw the foo(), bar() sequence in Zig, you'd know that bar() always executes after foo(). If it were possible for foo() to return an error, that code wouldn't compile unless the callsite handled the error explicitly with a try. The try tells the reader that there's a potential control flow depending on whether foo() throws an error.[0] [0] https://ziglang.org/documentation/0.11.0/#try https://ziglang.org/documentation/0.11.0/#try
- zozbot234 3y agoIn Rust, foo() might panic but this is only supposed to be used for truly unrecoverable errors. For most recoverable failure conditions you're supposed to use foo()?; which makes it clear that execution might not proceed to bar();
- wiseowise 3y ago> In Zig, the compiler forces you to handle exceptions (errors) at the callsite, so you can see from looking at function calls at the callsite what the potential control flow looks like. Damn, if only Java had something like that. Where you can see from function declaration whether it can throw something. Like if you could check exception. We could call it checked exceptions. And community would certainly like them.
- summerlight 3y agoI guess it's probably clearer if it's clarified as "no hidden function calls". It looks like the author wanted to generalize it because of no language level exception handling, but this could be misleading since platform level exception handling can override anything which makes it technically false.
- ta8645 3y ago> What article describes are abstractions. Abstractions are not bad. Abstractions are still possible, the only difference is the syntax with which they're presented. For instance, you need an "add" function for your addition abstraction, rather than overloading the + symbol. The only thing missing in Zig is the syntactic sugar of such abstractions; the argument being that such sugar obscures more than it illuminates.
- breadwinner 3y agoI would rephrase it as "no hidden function calls". Hidden function calls can make it a nightmare to debug code. It happens way too often in C++ code, less often in C#. But here's a C# example to illustrate the problem: https://web.archive.org/web/20021003203744/http://www.geocities.com/csharpfaq/test2.html https://web.archive.org/web/20021003203744/http://www.geocit...
- adontz 3y agoAs I said, abstractions can be abused. OK, your terminology, hidden function calls can be abused. Does not mean not having them is good.
- breadwinner 3y agoHaving fewer footguns is a good thing. When you inherit a codebase, if it is written in a language that has fewer footguns than one that does, that can make a big difference.
- adontz 3y agoBy this logic assembler is the best, as the most explicit language. I believe "number of footguns" is a metric people use for C++ exclusively. C++ is a mix of a few generations of a few languages, but most importantly several cultures. C++ is not bad. Qt code which uses STL here and there and a few unwrapped C libraries is bad. In that situation you really don't know what a "+" does in a particular case. In Python or C# situation is quite different. For example I struggle recall a single case from my experience when property was confusing or was used in a confusing manner.
- int_19h 3y agodefer has one important difference to try/finally - it places the cleanup code right next to initialization, which makes things easier to read overall.
- adontz 3y agoDeveloper may place defer close enough, it does not have to be close. RAII is better by this logic, but too "hidden" by Zig standard I guess.
- jmull 3y agoI don't think the point is about abstractions... it's how much you can understand about how the code executes by reading it. Abstractions are fine, of course. In Zig, though, they should be explicit and clear. E.g., the only way to call a function is by name, using the function-calling syntax. Control flow depends only on keywords and syntax directly in front of you. I think they do assume you known the language -- if you don't then I guess a lot might be unclear when reading code! -- but on the other hand, it's on the simpler, smaller side.
- TUSF 3y ago> Is it still so after ditching LLVM? Zig hasn't ditched LLVM, nor does it really plan to. What's planned is for the main Zig executable to not directly depend on LLVM, that way contributors to the compiler can still develop on the code base without needing to set up and compile LLVM on their systems. Zig does plan to eventually supersede LLVM's functions with their own custom backends, but in the short term, this only means using the new backend as a debug compiler (for faster compilations, to allow for a better developer feedback loop) and it won't be until the distant future that LLVM could feasibly be dropped as a dependency entirely, if the devs ever decide to actually go through with that.