Don’t Worry About Anything, Just Call Us

Callbacks are great and always have been. Long ago, we didn’t know we were injecting control or inverting dependencies; we just used them. When closures appeared, I did not see a huge difference: a little state here, a little context there. I have found my Closures Killer App: remote cleanup

Here is an example in Go:

In the calling code (with dependencies on DataDog, Redis, etc.)

type cleanupSignature  func(aName, aType string) func()

cleanupFactory := func(aName, aType string) func() {
    if _, found := SpanFromContext(context); !found {
        span, _ := datadog.SpanFromContext(context, aName, aType)
        return func() {
            span.Finish()
        }
    } else {
        return func(){}
    }
}

baz := foo(cleanupFactory, bar)

// ...

In the called code (with no dependencies on context, DataDog, etc.)

func foo(cleanupFactory cleanupSignature, zap int) string {
    cleanupFunction := cleanupFactory("my name", "my type")

    defer cleanupFunction()  // this is like a finally, but at the top of a function

    // ...

The cleanupFactory is more than a factory: in the example, it might create and start a DataDog Span. It closes (encapsulates) the caller’s context and reference to DataDog. It decides what cleanup its actions need, possibly being no actions at all. If the factory creates and starts a Span, the function it returns encapsulates the Span reference it needs to clean up. The host function has no knowledge or access to this value

Rather than the called function foo() holding extra values returned from the factory to control if and how the cleanup function works, the factory always returns only a simple function which foo() blindly calls. If nothing needs doing, the cleanup function is a nop. If it needs to do things, the cleanup function has encapsulated the values it needs rather than requiring foo() to pass it arguments

from a story by Nick Potts

 
0
Kudos
 
0
Kudos

Now read this

The Futures of Python

Futures defer execution of code. They can allow code to wait for external resources like file reads, network calls, and database access, and then automatically continue without stopping every other operation. They allow the definition... Continue →