Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function types vs single method interfaces

Tags:

If an interface has only a single method, should I use a function type instead?

Here are an examples of both approaches:

type Delegate interface {                 | type Delegate func(x int) int   Do(x int) int                           |  }                                         |                                            |  type App struct {                         | type App struct {   delegate Delegate                       |   delegate Delegate }                                         | }                                           |  func (this *App) foo() {                  | func (this *App) foo() {   ...                                     |   ...   y := this.delegate.Do(x)                |   y := this.delegate(x)   ...                                     |   ... }                                         | }                                           |  func main() {                             | func main() {   delegate := &DelegateImpl{}             |   delegate := &DelegateImpl{}   app := &App{delegate}                   |   app := &App{delegate.Process}   ...                                     |   ... }                                         | } 

Tests:

type FakeDelegate {                       |    t *testing.T                            |    expectedX int                           |    result int                              |  }                                         |                                            |  func (this *FakeDelegate) Do(x int) int { |    require.Equal(t, this.expectedX, x)     |    return this.result                      |  }                                         |                                            |  func TestAppFoo(t *testing.T) {           | func TestAppFoo(t *testing.T) {   app := &App{}                           |   app := &App{}   app.delegate = &FakeDelegate{t, 1, 2}   |   app.delegate = func(x int) int {   app.foo()                               |     require.Equal(t, 1, x) }                                         |     return 2                                           |   }                                           |   app.foo()                                           | } 

It looks like the code on the right (with function type) has less lines, especially when it comes to tests. But isn't there any pitfalls?

like image 303
Abyx Avatar asked Aug 12 '15 09:08

Abyx


People also ask

How many methods can a functional interface have?

// It can contain any number of Object class methods. A functional interface can extends another interface only when it does not have any abstract method. In the following example, a functional interface is extending to a non-functional interface.

What is the difference between a function and a functional interface?

Function: The Function interface has an abstract method apply which takes argument of type T and returns a result of type R. Its prototype is A functional interface has only one abstract method but it can have multiple default methods.

What is a single abstract method interface?

An Interface that contains exactly one abstract method is known as functional interface. It can have any number of default, static methods but can contain only one abstract method. It can also declare methods of object class. Functional Interface is also known as Single Abstract Method Interfaces or SAM Interfaces.

What is the difference between marker interface and functional interface in Java?

When an interface contains only one abstract method, then it is known as a Functional Interface. 2. Marker Interface: An interface that does not contain any methods, fields, Abstract Methods, and any Constants is Called a Marker interface. Also, if an interface is empty, then it is known as Marker Interface.


1 Answers

In the general case

This is a question of design. Interfaces offer something that functions don't : dynamic dispatch. So if later on you want (possibly your own) client code to apply said function to an object, and envision that this object may possibly be of one of several different types at one given point in the program, go for an interface.

The pro : you can get flexible.

The cons :

  • dynamic dispatch costs a minor overhead in execution time. You won't want that in the very middle of a critical loop for instance.
  • interfaces, if available, will be used as the system grows, possibly in slightly unexpected ways. Which means that whereas most times you can define a function's scope of responsiblity light-heartedly enough, an interface's responsibility and type signature should be well thought-out, as a design decision.
  • there are more intellectual indirections to go through for a reader who tries to understand the code.

Go is designed as a simple and pragmatic language. I suppose that as willing users, we should carry forward its philosophy. Hence, I'd say : if you don't need something, don't use it. :)

In your particular case

Although a function pointer is indeed a form of developer-managed dynamic dispatch, it seems to me that the reasoning above remains applicable : go for the simplest solution that could satisfy the foreseeable needs. Otherwise Go will become Java. If you're certain that the delegate will never need to provide any other entry point (like providing meta information for example), I'd say stick to the function pointer.

like image 97
Mathias Dolidon Avatar answered Oct 03 '22 05:10

Mathias Dolidon