4 ms·
>90s style "if error" check What makes it '90s style' other than you don't like it? Calling something "90s style" and its alternative "modern" is a thought-te
by memefrog 3y ago
>90s style "if error" check
What makes it '90s style' other than you don't like it?
Calling something "90s style" and its alternative "modern" is a thought-terminating cliche.
- deleted 3y ago[deleted]
- kaba0 3y agoThere have been many discussions on the topic of go’s error handling, the main gripes of people can be summarized as: - it returns both a return value and the error value, not xor. The convention is to use the error value only if returned, but sometimes the other “slot” is also used. If you squint a bit, this is exactly what errno does in C. The better, ML-y or exception-y way gives you a sum type instead, which can’t be mishandled. - you have to handle it in-place with no convenient shorthand allowing for handling it at another layer (and usually that’s the only meaningful way forward). Also, error handling is a cross-cutting concern, squeezing it inside your business logic is (in my opinion) a bad thing.
- memefrog 3y agoIt's not what errno does in C. errno in C is a thread-local variable which means accessing it is inefficient (it uses thread-local storage, which is much more expensive than a local variable) and you have to do awful things like save errno at the beginning of signal handlers if you call a function in the signal handler that can set errno (basically: any library function). Whether or not it's better to have a sum type (IMO it isn't), what Go has isn't anything like errno. errno is an ugly wart on the POSIX interface, which is otherwise quite nice. For example, Linux system calls directly return negative error codes, which is a much better way of handling errors, and then the libc has to set errno and return -1. Awful. >- you have to handle it in-place with no convenient shorthand allowing for handling it at another layer (and usually that’s the only meaningful way forward). Also, error handling is a cross-cutting concern, squeezing it inside your business logic is (in my opinion) a bad thing. That you say this and then advocate for optional<T>/result<t,e> is insane. That's exactly what a sum type does: it squeezes error handling into your business logic. And no, papering over that with ugly ? operators everywhere is not a solution, it is syntactic sugar. Error handling is part of the logic of your program. It is not just some 'ah we'll return it' thing. Many operations can fail and many errors are recoverable.
- kaba0 3y ago> errno in C is a thread-local variable which means accessing it is inefficient Which is an implementation detail, has nothing to with its semantics what we discuss here. Certain C compilers do wild things with errno as well. I’m not advocating for optional/result types, I personally believe that checked exceptions are the ideal solution, but it is a thoroughly underutilized tool in PL designs (Java has it, though it has many warts, but that is not inherent to the concept). Hopefully with the wake of effect-typed languages it could change. With that said, in Rust’s low-level case it makes sense to avoid exceptions, and sum types are an okay solution, especially if it has a handful macro for bubbling up. What go has is just straight up wrong.
- ssokolow 3y agoJava's ecosystem is moving away from checked exceptions because their "bolted onto the return type as a sidecar" design doesn't compose well with functional-style APIs. Monadic error handling (Rust's Option<T>/Result<T, E>) avoids that issue by putting the error inside the return type as a normal value. (Which is why, on multiple occasions, I've seen people call Result<T, E> "checked exceptions done right/properly".)
- kaba0 3y ago> checked exceptions done right/properly But they fail at including a stacktrace, autobubbling up, auto-unwrap and customizable "hit radius" with a try-catch block (okay, I'm sure some Monadic construct allows for that, but e.g. Rust's version does not).
- steveklabnik 3y agoTry blocks exist in Rust nightly, but given that an IIFE closure gives nearly the same results, there hasn't been a ton of pressure to stabilize them. I wish the team would though.
- ssokolow 3y ago1. Remember that Rust takes a Minimum Viable Product approach to 1.0 releases. There are experiments in adding stack traces in third-party error-handling crates that could eventually lead to additions to the standard library, but we've already gone through at least three iterations (error-chain, failure, anyhow, and possibly eyre) and already have two deprecated methods forever stuck on the standard library Error trait, so they're taking it slowly. (Plus, true exception handling is messy for a language that cares so much about FFI. Look at the discussions surrounding how panic! unwinding should behave at FFI boundaries.) 2. I think completely automatic bubbling would be a misfeature, and the `?` operator is a good balance between concise ease-of-use and the Rust focus on "code is read far more often than it's written". 3. Again, the `?` operator. I think completely automatic unwrap would also be a massive footgun and comprehension hazard. 4. As mentioned in the other reply, try blocks are in development. (See my previous comment about Rust adopting a Minimum Viable Product approach to v1.0) https://caniuse.rs/ https://caniuse.rs/ is a great illustration of how far we've already come and how minimal Rust 1.0 was.
- erik_seaberg 3y agoThat's when automated error handling began to be widely supported in early versions of mainstream languages: C++ (1985), Perl (1987), Python (1991), Java (1995). As time passes, I think it's healthy for us to expect new languages to learn from history and launch with more complete feature sets.
- memefrog 3y ago'Automated error handling' is a misfeature in a language where correctness matters. Perl and Python can use exceptions and there it makes sense. It makes no sense for a language without garbage collection and frankly the only system where it actually works well is Common Lisp, which has restarts. Without restarts, exceptions are just error codes but with spooky action at a distance.
- kaba0 3y agoWhat does having/not-having a GC have to do with correctness?
- ssokolow 3y agoIt's been said many times that Go feels like a language written by people who stopped paying attention to programming language research after the 1990s, as well as that it was written by people who look at C and think the only things that are less than perfect about it in the modern world are memory-safety and lack of a first-class concurrency story. Some examples (not an exhaustive list): 1. Fibers/stackful coroutines (See "Fibers under the magnifying glass" by Gor Nishanov for why they were hugely popular in the 90s and then got abandoned by all the major OSes and programming languages → http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2018/p1364r0.pdf http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2018/p136...) 2. Garbage collection (The 90s were the height of GC hype, to the point that the JVM still struggles with "Don't worry. GC research will make it fast." design decisions.) 3. Error handling that feels like "Well, we know that exceptions were a mistake, so the only other option is C-style return values... but, hey, we can at least follow 90s Python's lead in supporting returning tuples." (Granted, exceptions DO bake in a fundamental assumption that all the world can be treated as single-threaded execution amenable to transactional rollback. → https://www.lighterra.com/papers/exceptionsharmful/ https://www.lighterra.com/papers/exceptionsharmful/) 4. No generics until they were pushed into it by things like people writing preprocessors that use the Canadian Aboriginal Syllabics characters that look like angle brackets. (https://www.reddit.com/r/rust/comments/5penft/parallelizing_enjarify_in_go_and_rust/dgs72h8/?context=2 https://www.reddit.com/r/rust/comments/5penft/parallelizing_...) 5. No sum types (Bear in mind that sum types have been around since ALGOL 68 and, on many fronts, C was a step backward that the entire industry copied) 6. Dependency management that was only a hair above "just `git clone` it into your project" for most of Go's lifetime An example of such a reference would be this quote by rfiat at https://news.ycombinator.com/item?id=31603329 https://news.ycombinator.com/item?id=31603329 > It's interesting that you find Go to be Rust-adjacent. Setting aside the USPs of each language (goroutines and borrow checker respectively) and just speaking about the general experience of writing code, I find Go painful for all the reasons that I find Rust pleasant. > The best summary I can give of Rust is that it was designed by people who learned from the mistakes of the programming languages that came before it. The best summary I can give of Go is to quote Rob Pike's response [0] to a request for syntax highlighting in the Go playground: >> Syntax highlighting is juvenile. When I was a child, I was taught arithmetic using colored rods (http://en.wikipedia.org/wiki/Cuisenaire_rods http://en.wikipedia.org/wiki/Cuisenaire_rods). I grew up and today I use monochromatic numerals. > [0] https://groups.google.com/g/golang-nuts/c/hJHCAaiL0so/m/kG3BHV6QFfIJ https://groups.google.com/g/golang-nuts/c/hJHCAaiL0so/m/kG3B... dgunay's reply in that same thread ended on the summarization "I like Go and I feel very productive in it, but its commitment to simplicity is dogmatic in many ways and it very much is missing milestone advancements in PLs from the past several decades. It could easily have been made in the 90s."