3 ms·
It 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
by mtlynch 3y ago
It 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.
- jjnoakes 3y agoThat still doesn't show you at the call site.
- bvrmn 3y agoYeah but in Zig there is flexibility how you want to handle the error opposed to Java. You don't need to rewrap everything in RuntimeException and error sets allows to specify extended set of errors without much boilerplate.
- mr_00ff00 3y agoI don’t think you can ever argue that a small (and only non-runtime exception, right?) signature at the top of the function makes it easy to see what lines throw. Even if a function is small, each and every line could be the thrower and not allow the rest to execute.
- int_19h 3y agoJava exception specifications are annoying for two reasons. Firstly, there's no syntactic sugar to easily rewrap and propagate. Secondly, there is no way to generalize your error handling logic - i.e. for one component to say "I want to use something that implements this interface, and I don't care what errors it throws, but I do want to propagate them all". Zig doesn't have either problem.
- speed_spread 3y agoJava has @SneakyThrows. Fight me.
- anonymoushn 3y agoJava has a whole system of annotations that seems designed to make it impossible to figure out what code will actually be run, apparently designed by someone who thought lisp macros were too explicit.
- int_19h 3y agoWhich is a hack that amounts to throwing one's hands up and declaring, "we couldn't make it work properly".
- speed_spread 3y agoWho couldn't make it work properly, the language designer, the stdlib writers or the Java programmers? There is no way to make e.g. InterruptedException "work properly" as a checked exception since there is nothing intelligent one can do about it that's specific to this exception class. Rewrapping as RuntimeEx is just as much weaseling out but using more code and messing up stack trace for no good reason. Also, thanks for answering my request for a fight. Winter is boring.
- int_19h 3y agoThe language designers, because they wanted to have checked exceptions without the complexity of genericizing them. Exceptions that aren't meant to be handled really shouldn't be exceptions in the first place, but that's a separate design issue.
- jeroenhd 3y agoThis is why I will never stop trying to insert throws declarations into code I write. For some reason, Java developers seem to like hiding the fact their function can throw exceptions. The syntax problem gets mentioned a lot ("we'll just end up catching and rethrowing it anyway") but at that point you can just add throws to the calling method.
- chongli 3y agoCan't foo() call std.os.exit()? Then you don't know that bar() will always execute after foo() in Zig.
- mtlynch 3y agoYes, but I don't really think of that as hidden control flow. I know that if foo() returns, bar() will execute next, but foo() might not return (due to panic, program shutdown, or infinite loop). From my experience, when there's surprising behavior in software, I've frequently been surprised by silent exceptions, but I can't think of any time when I was surprised by control flow because a function intentionally shut down the program.
- adontz 3y agoBasically your argument is that strncat is more readable and easier to understand than std::string::operator+