debuggoMinor
Getting rid of goto without duplication in Go
Viewed 0 times
ridwithoutduplicationgettinggoto
Problem
Consider the following function:
I think this way of error handling is ugly. Is there a way to get rid of the goto without duplicating the call to
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:
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.
- You can use a
try..finallyblock. Simply returnnilor the proper pair andfinallywill trigger either way to do cleanup. This is the equivalent of C#'susing, 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 justfail()) 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.