Hacker News new | ask | show | jobs
by shurcooL 4703 days ago
If the language supported exceptions, how would you write this func?

  func (g *Gopher) DumpBinary(w io.Writer) {
    // Ignore all errors
    _ = binary.Write(w, binary.LittleEndian, int32(len(g.Name)))
    _, _ = w.Write([]byte(g.Name))
    _ = binary.Write(w, binary.LittleEndian, g.Age)
    _ = binary.Write(w, binary.LittleEndian, g.FurColor)
  }
3 comments

The language supports exceptions (panics). You could do something like (this is untested code):

  func panicBinaryWrite(w io.Writer, b binary.ByteOrder, data interface{}) {
    if err := binary.Write(w, b, data); err != nil {
      panic("Error in binary.Write")
    }
    return
  }

  func panicWrite(w io.Writer, data interface{}) {
    if _,err := w.Write(binary.LittleEndian,data); err != nil {
      panic("Error in io.Writer#Write")
    }
    return 
  }

  func ignoreErrors(f func()) {
    defer func() { 
      _ = recover()
    }()
    f()
    return
  }

  func (g *Gopher) DumpBinary(w io.Writer) {
    // Ignore all errors
    ignoreErrors(panicBinaryWrite(w, binary.LittleEndian, int32(len(g.Name))))
    ignoreErrors(panicWrite([]byte(g.Name)))
    ignoreErrors(panicBinaryWrite(w, binary.LittleEndian, g.Age))
    ignoreErrors(binary.Write(w, binary.LittleEndian, g.FurColor))
  }
It's trivial to write a function to ignore exceptions if that's what you want.

    def ignoreExceptions[A](a: => A): Unit = try {a} catch {case _ =>}

    def dumpBinary(g: Gopher, w: Writer) = {
      ignoreExceptions binary.Write(w, binary.LittleEndian,     int32(len(g.Name)))
      ignoreExceptions w.Write([]byte(g.Name))
      ignoreExceptions binary.Write(w, binary.LittleEndian, g.Age)
      ignoreExceptions binary.Write(w, binary.LittleEndian, g.FurColor)
    }
Though honestly I think a better solution is monads.

    //returns Validation - either success, or the first error (which stops processing)
    //return values are directly accessible, because later code won't run unless earlier code succeeds
    for {
      _ <- binary.Write(w, binary.LittleEndian, int32(len(g.Name)))
      _ <- w.Write([]byte(g.Name))
      _ <- binary.Write(w, binary.LittleEndian, g.Age)
      _ <- binary.Write(w, binary.LittleEndian, g.FurColor)
    } yield {}
    //Runs all the operations, ignoring errors
    //type system will force you to check a return value before you can use it
    binary.Write(w, binary.LittleEndian, int32(len(g.Name)))
    w.Write([]byte(g.Name))
    binary.Write(w, binary.LittleEndian, g.Age)
    binary.Write(w, binary.LittleEndian, g.FurColor)
Laziness and irresponsibility aside, why would you be writing code without even a minimal level of error checking?