4 ms·
A related musing about Go I wrote somewhere else before... Option types as well as lack of support for things like either and generics are why Go quickly becam
by codygman 12y ago
A related musing about Go I wrote somewhere else before...
Option types as well as lack of support for things like either and generics are why Go quickly became unappealing to me for real world work.
Check out this haskell example (note that the exceptions are values as well, so this is more flexible than most languages try or panic in Go):
failureExample :: IO (Either SomeException (Response LBS.ByteString))
failureExample = try $ do
get "http://www.httpbin.org/status/200"
get "http://www.httpbin.org/status/200"
get "http://www.httpbin.org/status/200"
get "http://www.httpbin.org/status/404"
main = failureExample >>= \case
Right r -> putStrLn $ "The successful pages status was (spoiler: it's 200!): " ++ show (r ^. responseStatus)
Left e -> putStrLn ("error: " ++ show e)
The equivalent Go is much longer and needlessly verbose:
func failureExample()(*http.Response) {
// 1st get, do nothing if success else print exception and exit
response, err := http.Get("http://httpbin.org/status/200")
if err != nil {
fmt.Printf("%s", err)
os.Exit(1)
} else {
defer response.Body.Close()
}
// 2nd get, do nothing if success else print exception and exit
response2, err := http.Get("http://httpbin.org/status/200")
if err != nil {
fmt.Printf("%s", err)
os.Exit(1)
} else {
defer response2.Body.Close()
}
// 3rd get, do nothing if success else print exception and exit
response3, err := http.Get("http://httpbin.org/status/200")
if err != nil {
fmt.Printf("%s", err)
os.Exit(1)
} else {
defer response3.Body.Close()
}
// 4th get, return response if success else print exception and exit
response4, err := http.Get("http://httpbin.org/status/404")
if err != nil {
fmt.Printf("%s", err)
os.Exit(1)
} else {
defer response4.Body.Close()
}
return response4
}
func main() {
fmt.Println("A failure.")
failure := failureExample();
fmt.Println(failure);
}
This code is all tested/runs and I might be putting this along with other issues I've had in a blog post, but no promises. I think this makes it very apparent why some people have an issue with Go, namely that it feels like going backwards and ignores lots of prior research at the altar of some deluded notion of pragmatism. I say that despite a Go Gopher staring at me on my desk.
- Zikes 12y agoI'm not familiar with Haskell so I can't exactly follow what you're trying to do, but I can take a stab at improving what your Go code is doing: package main import ( "fmt" "net/http" ) func main() { for _, url := range []string{ "http://httpbin.org/status/200", "http://httpbin.org/status/200", "http://httpbin.org/status/200", "http://httpbin.org/status/404", } { fmt.Printf("%s: %d\n", url, checkUrl(url)) } } func checkUrl(url string) int { response, err := http.Get(url) if err != nil { panic(err) } defer response.Body.Close() return response.StatusCode } You say of your Haskell code that errors are values, and Go is no different in this regard. checkUrl could easily be modified to return (int, error) and return both values, rather than panicking when an error occurs.
- codygman 12y agoCool, that's a good refactoring. What if we don't care about the errors and just want to return nil or the value. The caveat is that when any of your http requests get a non 200 response code no further processing is done and nil is returned.
- Zikes 12y agoWhat I would do in that case is modify checkUrl to return a bool, change the return to return response.StatusCode == 200, and change the for loop contents to if !checkUrl(url){ fmt.Printf("Non-200 response for %s", url) break }