11 ms·
It's 'interesting' that the author critices Go for having a GC making it 'inappropriate' as a system programming language, but then also critices Go for not hav
by flohofwoe 4y ago
It's 'interesting' that the author critices Go for having a GC making it 'inappropriate' as a system programming language, but then also critices Go for not having exceptions (which are IMHO at least as 'inapproriate' for that type of language).
If anything, the latest round of systems programming languages which all use error unions instead of exceptions have demonstrated quite clearly that exceptions are actually quite pointless.
- zozbot234 4y agoGo does have exceptions, via panic/recover. You could argue that Rust lacks true exceptions because a Rust panic can be configured to be fatal at the whole-program level. (Which is actually great for deep-embedded scenarios where even C++ use is with no-exceptions support.)
- usrnm 4y agoYeah, it's funny how go does have exceptions, but no notion of exception safety. Manual mutex locks/unlocks are everywhere, and don't even start me on defer, which is just terrible
- mike_hock 4y agoThat's how you get a "simple" language.
- IshKebab 4y agoThose are not exceptions by most reasonable definitions. Exceptions are a general purpose error handling method. Try, catch and all that. They are almost always objects with multiple types. Go and Rust's panic is for unrecoverable errors. They both have the ability to catch panics because sometimes you really need to do that (e.g. when interacting with FFI or sometimes multithreaded code). They are not exceptions though. I've seen this myth repeated a few times lately (always about Go and not Rust for some reason) and I wish it would die. You wouldn't say C "has exceptions" would you?
- pipologist 4y agoThat’s being stuck on usage patterns. Any automatic stack unwinding mechanism is the same. Whether C++ exceptions and Rust’s panics.
- dureuill 4y ago> You wouldn't say C "has exceptions" would you? Maybe that's just me, but I wish more people would say that C "has exceptions", if only because longjmp/setjmp[0] interacts with exception systems of other languages, sometimes badly. That being said, I think an important difference is that in C setjmp/longjmp do not "unwind" objects, due to the lack of destructors. However panics at least in Rust are just exceptions by another name. The difference solely comes from culture. Even the fact that unwind can be turned to abort is not significant, considering that pretty much all production implementations of C++ have fno-exceptions [0]: https://learn.microsoft.com/en-us/cpp/cpp/using-setjmp-longjmp?view=msvc-170 https://learn.microsoft.com/en-us/cpp/cpp/using-setjmp-longj...
- IshKebab 4y ago> That being said, I think an important difference is that in C setjmp/longjmp do not "unwind" objects, due to the lack of destructors. I don't think that is a requirement of exceptions. It's just a sensible thing that most implementations do. > The difference solely comes from culture. Maybe, but that is a huge difference! You can implement anything in any Turing complete language but you wouldn't say that they all "have" every feature... To quote https://doc.rust-lang.org/std/panic/fn.catch_unwind.html https://doc.rust-lang.org/std/panic/fn.catch_unwind.html : > It is *not* recommended to use this function for a general try/catch mechanism. The Result type is more appropriate to use for functions that can fail on a regular basis. Additionally, this function is not guaranteed to catch all panics, see the “Notes” section below.
- mgaunard 4y agoThere is nothing about exceptions that's inappropriate for system programming. If anything it enables the enforcement of strong invariants and leads to better and safer code.
- masklinn 4y ago> There is nothing about exceptions that's inappropriate for system programming. There's lots about exceptions which is inappropriate for system programming, starting from FFI unsafety and the lack of signaling to callers (which makes resilient use more difficult). > If anything it enables the enforcement of strong invariants It doesn't do that. > and leads to better and safer code. It only does that in comparison to truly deficient (e.g. c-style) error reporting, and that's being generous.
- mgaunard 4y agoWell it seems you don't understand exceptions. They eliminate erroneous states entirely, since the objects just don't get created if an error occurs. The alternative that the parent said was making all of your state be a union with some kind of error, and making sure all accesses handle the fact the variable might be in a erroneous state. That is a huge explosion of possible states in your program, and essentially making every invariant weak everywhere. Then FFI, I suppose you mean interfacing with C. Problems that arise when interfacing with other programming languages are orthogonal to a language's ability to be used for system programming. Obviously you wouldn't let an exception propagate through some C code, that's forbidden.
- dmitriid 4y ago> the latest round of systems programming languages which all use error unions instead of exceptions have demonstrated quite clearly that exceptions are actually quite pointless. What they have actually shown is that error unions are not a panacea and a pain to handle manually. And that hardcore killing your app in the presence of even the tiniest of unhandled errors isn't suitable for any programming, especially systems programming. That's why Rust ended up introducing try!, ? and catching panics. Go also added panic recovery.
- zozbot234 4y agotry! and '?' is just a syntactic convenience for passing error returns to the caller. It's not even monad-like because the outer code still has to wrap the happy path return with Some(...) or Ok(...), which wouldn't be the case with an actual monad. (I.e. it's quite different from what was done with "async fn" support, where the Future return type is hidden via the 'async' specifier and the control flow is totally changed.)
- dmitriid 4y ago> try! and '?' is just a syntactic convenience for passing error returns to the caller. Indeed. Because manually handling those are a pain in the butt. So they made a shortcut. That still needs to be handled by someone up in the hierarchy. Exceptions in all but name. > It's not even monad-like because No one cares whether it's monads or not.
- moloch-hai 4y ago> Exceptions in all but name. But with added space and branch-predictor overhead in every call site, and runtime overhead in every call event!
- tialaramex 4y agoThe crucial thing about Try (the ? operator) is actually pretty easy to see if you look at the Trait which makes it go: The result of the branch method on Try is ControlFlow<Self::Residual, Self::Output> Try isn't stable, but ControlFlow is. They've reified the control flow! Rust has a type which represents the idea of a decision whether to return early. This is in my opinion pure genius, and it happened almost by accident. It seemed natural at first that the decision to return early is manifested directly in Result, but it isn't. That's the insight. Failure and returning early are distinct ideas, and we might just as easily want to return early in consequence of success as failure. In separating "Success versus Failure" from "Return early versus keep going" Rust gets a lot more value here than is encapsulated in C++ Exceptions.
- okanat 4y agoSystem programming doesn't mean kernel and embedded only. The huge portion of C++ programs are running in the user space because one may still want performance benefits, direct access to memory via well-defined struct layout and direct calls to the system libraries to get maximum functionality from the OS. User space programs can handle exceptions.
- woooooo 4y agoSure, but that argument also applies for GC. I suppose there's a window where you can't tolerate GC pauses but can have exceptions allocating memory unpredictably, but it's a pretty small window.
- usefulcat 4y ago'Performance benefits' may also include low and/or predictable latency. GC is a real problem there. Not insurmountable by any means (witness the number of people who use java for latency sensitive applications), but a problem nonetheless. Edit: Also, depending on how they're used, exceptions can be easier to avoid than GC. IOW, if an exception has been thrown at all, you may well have bigger problems than the latency cost of throwing.
- kllrnohj 4y agoOn the contrary, that window is both huge and also you're assuming exceptions require expensive allocations but they don't. Exceptions are for exceptional situations, so the performance impact of them when thrown is rarely of concern - both in C++ and in pretty much every other language with exceptions. There's a reason something like Java still uses error return values for an awful lot of things, after all. But importantly exceptions means that you're not doing return value checking for errors that rarely happen, which can get expensive on the whole. As in, exceptions gives your code a path to both be cleaner and faster on average - they are really very useful when implemented well. The problem with C++ exceptions has nothing to do with the memory allocation cost when thrown (which as mentioned, there's other strategies you can deploy than the default of just `new`). Rather it comes from the significant impact on binary size and the reliance on RTTI.
- alphanullmeric 4y agoExceptions have zero cost when not thrown, apart from being included in the binary
- pornel 4y agoA mere possibility of a function throwing an exception is a side effect that an optimiser can't ignore, and this inhibits many types of optimisations involving code motion. This is for example the main cost of bound checking in Rust, not the branches.
- AshamedCaptain 4y agoI always hear this, but these days entire Linux distros build with -fasynchronous-unwind-tables which has much more overhead than C++ exceptions, since now you have to provide an unwind path for every single instruction boundary. Even Chrome does it (for "accurate stack traces") when otherwise they're on the no exceptions camp. Using this option also completely subsumes the otherwise negligible cost of C++ exceptions, which only affects non-inlined function calls (which already limit code motion anyway).
- MoscMob 4y agoUnless you care about performance. Exceptions have a performance benefit in that there's no cost if they are not thrown. With returning error values, every caller up the chain has to test the error condition. We've used exactly for this reason to improve performance, albeit this was a long time ago.