8 ms·
I believe there are many languages that you could use that would have all of these features. That way you would have a language that would be more appropriate t
by jimjimjim 10y ago
I believe there are many languages that you could use that would have all of these features. That way you would have a language that would be more appropriate to your programming style without needing to add extra features to Go that possibly don't fit with Go's language style.
(Note: post edited to remove snark.)
- catnaroek 10y agoI don't see how `panic` and `recover` are any simpler than exceptions. Could you explain? P.D.: The downvote didn't come from me.
- jimjimjim 10y agoWell, they are kind of more difficult than exceptions, but I think that's the point. Handling errors by use of an exception mechanism is discouraged in idiomatic go. A big part of the style and simplicity comes from not needing to worry about what possible exceptions could come bubbling up from a library stack and under what conditions. Even though people complain about the repetition of "if err !=nil" at least you know from the function declaration if an error is could occur.
- catnaroek 10y agoFWIW, I don't have anything against checking errors - I agree that it's preferable to exceptions, but the way it happens to be done in Go is rather distasteful. A sum type, as suggested by TheDong, would make things clearer, by statically forcing the alternatives to be: (0) A correct result (and no error object) (1) An error object (and no correct result) Ruling out: (0) Both a correct result and an error object (1) Neither a correct result nor an error object By “ruling out”, I mean “it's a compile error”, rather than “it's a pattern, and the community won't appreciate it if you deviate from it”. Panics as normal control flow are just as unidiomatic in Rust as they are in Go, but at least: (0) There's a decent (in fact, superior) alternative for error handling. (1) You don't risk leaking resources. RAII has that covered.
- fauigerzigerk 10y agoI like the conceptual clarity of sum types, but in some cases they may not be flexible enough (same as exceptions). Consider the case of io.Reader: https://golang.org/pkg/io/#Reader https://golang.org/pkg/io/#Reader Read always returns the number of bytes read, and if an error occurs after some bytes have been read (or at EOF) it returns that error as well. It does feel a little dirty, but it's also efficient and pragmatic.
- catnaroek 10y ago> Read always returns the number of bytes read, and if an error occurs after some bytes have been read (or at EOF) it returns that error as well. Sum types can do this as well. In OCaml syntax: type result = | Success of int (* bytes read = buffer length *) | Error of int * err_info (* bytes read, error info *) class type reader = object (* attempt to fill the buffer *) method read : buffer -> result end > It does feel a little dirty, but it's also efficient and pragmatic. The pragmatic thing to do is to make illegal states irrepresentable, so that the programmer doesn't have to worry about them. There's literally no benefit to losing conceptual clarity.
- fauigerzigerk 10y agoI understand why this may be formally preferrable, but it still suffers from the same conceptual clarity issues. What I mean by conceptual clarity is knowing for sure, without looking at the documentation of each function, that it returns either an error or data for further processing, but never both. That's not the case with your solution either. You're just packaging the same conceptual ambiguity in a slightly different way.
- catnaroek 10y ago> That's not the case with your solution either. It is. A single call to the `read` method of a `reader` object returns either `Success` or `Error`, but never both. It's handled like this: match my_reader#read my_buffer with | Success(len) -> (* success logic *) | Error(len,info) -> (* error-handling logic *) > You're just packaging the same conceptual ambiguity in a slightly different way. There's no ambiguity whatsoever. The cases are separate, and you can't use the variables of one case when handling the other. There's still literally no reason to sacrifice conceptual clarity.
- dom96 10y agoYou can easily implement a feature which lists all possible exceptions that a specific function raises. Java has a feature called checked exceptions that ensure that you handle all possible exceptions in your program, although admittedly this feature is annoying. Another language called Nim[1], that is in fact a pretty good Go alternative, offers a similar feature[2]. But in Nim it's opt-in and the documentation includes information about each procedure and the exceptions it raises, this is shown by the `raises` pragma where `raises: []` means that no exception is raised. For example, you can easily see that `parseInt` may raise a `OverflowError` or a `ValueError` in the documentation[3] whereas `normalize` doesn't raise anything[4]. This information is inferred by the Nim compiler automatically. In my opinion this is the best of both worlds, because when your program does crash, you get a nice stack trace that is just as informative as Python's stack traces and you always know the exceptions that each procedure may raise. Here is an example stack trace from a compiler crash: Error: internal error: getUniqueType Traceback (most recent call last) nim.nim(97) nim ... msgs.nim(957) internalError msgs.nim(866) rawMessage msgs.nim(863) rawMessage msgs.nim(796) handleError 1 - http://nim-lang.org http://nim-lang.org 2 - http://nim-lang.org/docs/manual.html#effect-system-exception-tracking http://nim-lang.org/docs/manual.html#effect-system-exception... 3 - http://nim-lang.org/docs/strutils.html#parseInt,string http://nim-lang.org/docs/strutils.html#parseInt,string 4 - http://nim-lang.org/docs/strutils.html#normalize,string http://nim-lang.org/docs/strutils.html#normalize,string
- twic 10y ago> Java has a feature called checked exceptions that ensure that you handle all possible exceptions in your program, although admittedly this feature is annoying. I think it's mostly annoying because checked exceptions were used badly in the early years of Java, so there are methods which throw loads of unrelated exceptions which have to be handled separately. Better design of exception hierarchies, and the availability of multi-catch, makes this quite a bit better. Although it's recently got worse again because none of the shiny new stream stuff supports lambdas which throw checked exceptions. You have to either stick to unchecked exceptions and lose type safety, or probably better, rotate the exceptions sideways in type-space and use an Either: https://github.com/poetix/ambivalence/blob/master/src/main/java/com/codepoetics/ambivalence/Tryable.java https://github.com/poetix/ambivalence/blob/master/src/main/j...
- spriggan3 10y ago> I believe there are many languages that you could use that would have all of these features. That way you could use what you want and wouldn't have to complain about Go. We are talking about Go. Why do you basically say "f. you" to people when people points at some obvious flaws in the language ? people complain mostly because they are using it, if they were not, they wouldn't. Unfortunately your behavior is something I've seen often in the Go community.
- jimjimjim 10y agoI apologize for the tone of my original comment. I've altered it to be hopefully less offensive. But.. I was responding a post that was pointing out many things that are known to not be present in the language. These features weren't forgotten or missed they were excluded when the language spec was being decided.
- commentzorro 10y agoEven though all these features were purposely excluded by choice it's clear now in hindsight that some of these decisions are wrong. What I find so so weird is the tenacious responses when it's pointed out that Go has flaws. Why does Go get to be the one perfectly designed language? A decision can be made with tremendous thought but still be wrong.
- mixedCase 10y ago>it's clear now in hindsight that some of these decisions are wrong For some usecases. For which you can just import Cheney's package, some other or roll your own. Which is Go's point: simple by default. For what I'm doing with Go I do not need nor want anything more than a string, I do not need a debugger so I don't use Delve, I don't need logging more complex than what the std libs interface offers... So why should I carry all that sort of baggage by default? If you need that stuff, feel free to import the adequate package or use a language that fits your purpose better. IMO Go is better treated as a DSL than a general purpose language, although I think the same of most languages.