Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there any advantages to having a defer in a simple, no return, non-panicking function?

Tags:

go

Going through the standard library, I see a lot functions similar to the following:

// src/database/sql/sql.go
func (dc *driverConn) removeOpenStmt(ds *driverStmt) {
    dc.Lock()
    defer dc.Unlock()
    delete(dc.openStmt, ds)
}
...

func (db *DB) addDep(x finalCloser, dep interface{}) {
    //println(fmt.Sprintf("addDep(%T %p, %T %p)", x, x, dep, dep))
    db.mu.Lock()
    defer db.mu.Unlock()
    db.addDepLocked(x, dep)
}
// src/expvar/expvar.go
func (v *Map) addKey(key string) {
    v.keysMu.Lock()
    defer v.keysMu.Unlock()
    v.keys = append(v.keys, key)
    sort.Strings(v.keys)
}
// etc...

I.e.: simple functions with no returns and presumably no way to panic that are still deferring the unlock of their mutex. As I understand it, the overhead of a defer has been improved (and perhaps is still in the process of being improved), but that being said: Is there any reason to include a defer in functions like these? Couldn't these types of defers end up slowing down a high traffic function?

like image 564
Alexander Kohler Avatar asked Nov 15 '17 02:11

Alexander Kohler


2 Answers

Always deferring things like Mutex.Unlock() and WaitGroup.Done() at the top of the function makes debugging and maintenance easier, since you see immediately that those pieces are handled correctly so you know that those important pieces are taken care of, and can quickly move on to other issues.

It's not a big deal in 3 line functions, but consistent-looking code is also just easier to read in general. Then as the code grows, you don't have to worry about adding an expression that may panic, or complicated early return logic, because the pre-existing defers will always work correctly.

like image 158
JimB Avatar answered Nov 11 '22 05:11

JimB


Panic is a sudden (so it could be unpredicted or unprepared) violation of normal control flow. Potentially it can emerge from anything - quite often from external things - for example memory failure. defer mechanism gives an easy and quite cheap tool to perform exit operation. Thus not leave a system in broken state. This is important for locks in high load applications because it help not to lose locked resources and freeze the whole system in lock once.

And if for some moment code has no places for panic (hard to guess such system ;) but things evolve. Later this function would be more complex and able to throw panic.

Conclusion: Defer helps you to ensure your function will exit correctly if something “goes wring”. Also quite important it is future-proof - same reply for different failures.

So it’s a food style to put them even in easy functions. As a programmer you can see nothing is lost. And be more sure in a code.

like image 30
Eugene Lisitsky Avatar answered Nov 11 '22 07:11

Eugene Lisitsky