serum-errors/go-serum-analyzer

support for analyzing named function types like interfaces

Opened this issue · 1 comments

A named function type with an error-describing comment should be analyzable, and should be treated as roughly the same as an interface with a single function.

// Errors:
//
//   - example-error-foo -- etc, etc.
type NeatFunc func() error

func Consumer(fn NeatFunc) error { /*...*/ }

... should be equivalent to:

type Iface interface {
    // Errors:
    //
    //   - example-error-foo -- etc, etc.
    Do() error
}

type thing struct{} // No content -- don't care, just need it so we have something to attach methods to.

// Errors:
//
//   - example-error-foo -- etc, etc.
func (thing) Do() error {
    serum.Errorf("example-error-foo", "this was a lot of boilerplate")
}

func Consumer(fn Iface) error { /*...*/ }

Motivations:

  1. It's a golang feature and it would be good to support as best we can!
  2. Keystroke reduction! While using interfaces works fine... sometimes, one really only needs a single method, and introducing a whole interface produces a lot of additional keystrokes. The additional keystrokes begin to increase especially rapidly if a quick little anonymous function closure could otherwise be used: then, to use an interface requires values in the struct, lines for struct initialization (instead of just capturing values in the closure), etc -- often causing variable names to be repeated several times, which then makes maintaining that code a bit frustrating.

Right now, error description comments on a function type have no effect.

A practical example of a reason I want this:

I have an application that user a 3rd party library that takes a lot of callback parameters.

(Examples of this might be some kind of http server "router" library, or a CLI library like urfave/cli, or... you get the idea.)

Callbacks and callback-heavy APIs is one of the weak spots for the analyzer, where it generally has to stop tracing -- callbacks are a form of mutable state (or at least the reference to the callback itself generally is), and so to completely understand them would require "symbolic execution".. and that in turn is not just a non-feature of this analysis tool, but in fact is generally understood to be impossible to execute in practical time (as the wikipedia page well covers).

But I can recover a good amount of sanity fairly easily. Let's assume that the 3rd party library in question has an API where after I've loaded it up with a bunch of callbacks, I'm going to call one function of the library, and if it gives me back an error, it's going to be one of the errors may callbacks returned (maybe plus one or two others, which I'd still have to handle with custom code; whatever). So then... If I can gather all the error codes of all the callbacks in one place, and at least have the analyzer verify that list, that would help me a lot. (I'll still be writing custom code to sort everything back out, but even getting the list of errors in one place is a big win.)

And I can do that with interface. Just make all my callbacks implement the interface!

That's possible with full-blown interfaces, but in a callback-heavy API, you can see how full-blown interfaces and methods can add a large amount of boilerplate very quickly.