Hacker News new | ask | show | jobs
by eternalban 5017 days ago
I respectfully disagree: http://golang.org/src/pkg/net/timeout_test.go#L39

edit:

You should note that the above test code is actually far less verbose than the analogous end-user code, given that the timeout_test.go clearly expects the 'err' var to be a net.Error.

Now consider the case of a network subsystem, with funcs having in args of type 'bufio.Reader' and/or 'bufio.Writer'. At some prior point you may have set 'net.Conn.SetReadDeadline(aPointInTime)', and in your stream processing funcs you may naturally encounter either net.Error (due to timeout) or buffer overruns, etc.

What would call site look like? Can you safely cast to (net.Error) like the test code? Not unless you can live with panics on interface type mismatch.

   // hmm. what is the error type?
   _, e := readMessage(reader) 
   switch errType(e) { // you write this reflective func
   case NET_ERROR:
      if e.(net.Error).timeout() { /* handle timeout */}
   default:
         /* deal with other errors */
   }
2 comments

You are using an internal testing package as an example?

First you wouldn't cast to net.Error like the test code for real code. That code is testing internal details of the net package and not meant to be a guide for idiomatic consumption of the code at the level you are describing.

here is what you would actually do in production code:

    _, e := readMessage(reader)

    switch et := e.(type) {
    case net.OpError:
       // handle OpErrors specifically
      if et.timeout() { /* handle timeout */ }
    case net.AddrError:
      // handle AddrErrors specifically
    case net.DNSError:
      // handle DNS errors specifically
    case net.Error:
      // handle all the rest of the net packages errors
    default:
      // deal with other errors
    }
Of course that's just for low level code. if you want to see if net.Error has code leaking though the wrapping package then you would perhaps use a case looking for all the wrapper packages specific errors and then look for net.Error types after that.

Most of the time you won't be dealing with the net package either. Instead you will be dealing with the http package for instance where your errors will mostly look like this: http://golang.org/pkg/net/http/#variables for which you can use a regular switch. I have just listed both of my cases taken directly from the stdlib including the case you listed.

Not sure what buffer overruns you are referring to, or why this case requires reflection at all.

  err := readMessage(reader)
  if n, ok := err.(net.Error); ok && n.Timeout() {
      // handle timeout
  } else if err != nil {
      // handle other errors
  }
You can see an example of exactly this pattern here: http://golang.org/src/pkg/net/http/server.go?s=29962:30008#L...
You did not carefully read the GP.

IO read/write functions are not limited to the net package. net.Conn supports a subset of these (interface types) and it is entirely idiomatic and possible for a net.Conn flavor to endup at some deep layer of your code in a function accepting generic io in args.

Functions taking non-net "in args" returning "error" can not be assumed to always return "net.Error". You will need to test the type (reflectively) and then safely cast.

For example : http://golang.org/pkg/io/#ReadFull

Is it "non-idiomatic" to wrap net.Conn as another non-net package type and then use it?

http://golang.org/src/pkg/net/net.go#L22

To be clear, the two-valued cast I used in my example never panics. It returns (casted value, true) or (nil, false). No need to write any reflective functions.

As to your example of io.ReadFull: what about it? If it gets an EOF before filling the buffer you passed in, it'll return ErrUnexpectedEOF per the documentation. If it gets any other error, it'll return it instead. I haven't actually looked at the source in a while but that's how almost all of the byte stream functions work.