Interface vs first-class function

781 views
Skip to first unread message

Henry

unread,
Nov 20, 2016, 12:22:57 AM11/20/16
to golang-nuts
Hi,

I am wondering from best practice point of view whether it is better to use interface or first-class function, especially considering that Go encourages the use of small interfaces. Here is an example:

type SomethingDoer interface{
DoSomething(data Data)
}

func PerformWork(doer SomethingDoer){
//...
}

Or

type SomethingDoer func(Data)

func PerformWork(doer SomethingDoer){
//...
}

Is there some sort of a guideline when to use one vs the other? They seem like redundant features to me.

Thanks

Henry

atd...@gmail.com

unread,
Nov 20, 2016, 7:25:11 AM11/20/16
to golang-nuts
You have less indirection with the interface. More ergonomic.
An interface also allows to define a set of constraints whereas the first class function does not coerce you into having a defined set of function arguments.

atd...@gmail.com

unread,
Nov 20, 2016, 10:23:47 AM11/20/16
to golang-nuts
To be more concrete, taking your example, PerformWork cannot be easily customized according to the type of first class function that returns a func(Data).
Actually it goes further, because that first class function can "only" return a func(Data) and not multiple functions.

With an interface, it's equivalent to being able to pass a first class function returning possibly multiple values of which at least one is of type func(Data).
More than that, we have ways to discover some of the other return values and adapt PerformWork execution accordingly.

Chris Hines

unread,
Nov 20, 2016, 11:03:55 AM11/20/16
to golang-nuts
I tried to break down the thought process on this exact question earlier this year and gave a presentation at my local Go meetup. My slides are here: http://go-talks.appspot.com/github.com/ChrisHines/talks/non-orthogonal-choices-in-go/non-orthogonal-choices-in-go.slide

TL;DR

Informed choices for dynamic behavior

Use interface values when:
  • Well known interfaces already exist, e.g. io.Reader
  • More than one behavior required
  • Typically stateful
  • Implementations non-trivial

Use function values when:
  • Only one behavior
  • Typically stateless
  • In-line implementations typical
Hope it helps.

Chris

simon place

unread,
Nov 20, 2016, 8:27:06 PM11/20/16
to golang-nuts
you'll need interfaces if you want your 'thing' to leave the programs context, to store/transmit it.


Henry

unread,
Nov 20, 2016, 11:23:30 PM11/20/16
to golang-nuts
Thanks for the replies. In terms of future extensibility, is it safe to say that interface is superior to first-class functions?

Anmol Sethi

unread,
Nov 20, 2016, 11:25:07 PM11/20/16
to Henry, golang-nuts
In relation to this question, do you guys think it would have been better had http.Handler been a function, not an interface?

On Sun, Nov 20, 2016 at 11:23 PM Henry <henry.ad...@gmail.com> wrote:
Thanks for the replies. In terms of future extensibility, is it safe to say that interface is superior to first-class functions?

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Tamás Gulácsi

unread,
Nov 21, 2016, 12:39:36 AM11/21/16
to golang-nuts
I don't think so. A http.Handler usually has a ton of state, so a struct's method is handier than a closure.
And take a look at http.HandlerFunc!

Anmol Sethi

unread,
Nov 21, 2016, 1:34:50 AM11/21/16
to Tamás Gulácsi, golang-nuts
https://github.com/julienschmidt/httprouter https://github.com/pressly/chi and others actually use a function by default because it's the more common case. See https://github.com/pressly/chi/issues/94#issuecomment-254516724 



On Mon, Nov 21, 2016 at 12:39 AM Tamás Gulácsi <tgula...@gmail.com> wrote:
I don't think so. A http.Handler usually has a ton of state, so a struct's method is handier than a closure.
And take a look at http.HandlerFunc!

Colin Stewart

unread,
Nov 21, 2016, 3:21:15 PM11/21/16
to golang-nuts
A few other thoughts on this:

1 - Method values mean that you can get a function type that accesses state without closures over local variables:

a := &myStruct{}
// b is a SomethingDoer function
b := a.DoSomething

e.g. https://play.golang.org/p/SVY8rQ8WR_

2 - Method values also mean that multiple methods can be provided that satisfy a function type but operate on the same data, something that requires creating new types to do with interfaces (though very do-able - see SortWrapper example in https://golang.org/pkg/sort/)

a := &myStruct{}
// b and c are both SomethingDoer functions
b := a.DoSomethingAlphabetically
c := a.DoSomethingChronologically

3 - (In my view a minor point) - It's clearer at the call site as to which function is being called without an interface:

needsADoer (a.DoSomething) versus needsADoer (a)

I tend to use interfaces for things with multiple methods that need to work together and function types for single method abstractions.

Dave Cheney

unread,
Nov 21, 2016, 3:57:24 PM11/21/16
to golang-nuts
With a nod to Chris's excellent presentation, this may be an example of Go breaking its own orthogonality rules for the sake of being more consistent (the rule of least surprise)

There is a strong overlap between an interface with a single method and a function value, Tomás Senart spoke about this at last year's Gophercon, but as a function value cannot easily have two behaviours there is clearly a requirement for an interface with two or more methods (although SRP would tend to drive your design in the other direction, sometimes this is necessary) so an arbitrary restriction that an interface have more than one method would be surprising.

I think there is a strong parallel between this discussion and the occasional flair up of the "why does Go need new?" debate. The answer in both cases is while sometimes features appear to overlap in the simple case, they are actually independent. A small concession for consistency over orthogonality.

Dave

roger peppe

unread,
Nov 22, 2016, 6:15:38 AM11/22/16
to Henry, golang-nuts
From my point of view, the main difference is that interfaces are strictly
more powerful, because you can't dynamically type convert a function
type into something different.

You can always make an interface from a function (e.g. http.HandlerFunc
and the like) but not the other way around.

This is a real issue in some places - for example http.Handler is an interface,
but the popular github.com/julienschmidt/httprouter package's Handle
type is a function, which means that you can't use the same router to
(for example) store metadata about routes, because all you've got is
a function.

Another consideration is that a function is only one word, so if you're
likely to be using stateless non-closure functions, and putting them
into interface values, you'll incur less allocations.
Reply all
Reply to author
Forward
0 new messages