HiveBrain v1.2.0
Get Started
← Back to all entries
debuggoMinor

Getting rid of goto without duplication in Go

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
ridwithoutduplicationgettinggoto

Problem

Consider the following function:

func Listen(username string) (net.Listener, error) {
    path := filepath.Join(socketsDir, username)

    oldUmask := syscall.Umask(^0600)
    defer syscall.Umask(oldUmask)

    listener, err := net.Listen("unixpacket", path)
    if err != nil {
        return nil, err
    }

    passwd, err := passwd.Getpwnam(username)
    if err != nil {
        goto chownFailed
    }

    err = os.Chown(path, int(passwd.Uid), os.Getgid())
    if err != nil {
        goto chownFailed
    }

    return listener, err

chownFailed:
    listener.Close()
    return nil, err
}


I think this way of error handling is ugly. Is there a way to get rid of the goto without duplicating the call to listener.Close?

Solution

That's the standard C cleanup block, which is extremely widely used, you can see tons of examples just browsing the Linux kernel code. In more structured programming languages you have two (other) options:

  • You can use a try..finally block. Simply return nil or the proper pair and finally will trigger either way to do cleanup. This is the equivalent of C#'s using, which I consider to be very graceful and semantic code. In Windows using SEH, such a block is pretty much free in terms of performance, only actually throwing and stack unwinding takes time.



  • You can also define a lambda function at the beginning called cleanup() (or just fail()) and call it when appropriate. I consider this to be less elegant because if you forget to call it you'll have a leak.



Alternatively redesign your code to use RIAA. Go is a scoping language right? Like C++? Simply wrap your objects in a class and rely on destructors for cleanup.

Context

StackExchange Code Review Q#83639, answer score: 3

Revisions (0)

No revisions yet.