How HandlerFunc(f) convert a function to an interface type? - go

When check following code, got a doubt with type convert from function to interface.
Code
http_hello.go:
package main
import (
"fmt"
"log"
"net/http"
)
// hello http,
func helloHttp() {
// register handler,
http.Handle("/", http.HandlerFunc(helloHandler))
// start server,
err := http.ListenAndServe(":9090", nil)
if err != nil {
log.Fatal("ListenAndServe:", err)
}
}
// handler function - hello,
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, you've requested: %s\n", r.URL.Path)
}
func main() {
helloHttp()
}
The above code works.
(Then I tried to write a small program to check is this a general feature, but it won't work, check following code)
func_to_intf.go:
package main
import (
"fmt"
)
// an interface,
type Adder interface {
add(a, b int) int
}
// alias of a function signature,
type AdderFunc func(int, int) int
// a simple add function,
func simpleAdd(a, b int) int {
return a + b
}
// call Adder interface to perform add,
func doAdd(a, b int, f Adder) int {
return f.add(a, b)
}
func funcToIntf() {
fa := AdderFunc(simpleAdd)
fmt.Printf("%#v, type: %T\n", fa, fa)
a, b := 1, 2
sum := doAdd(a, b, fa)
fmt.Printf("%d + %d = %d\n", a, b, sum)
}
func main() {
funcToIntf()
}
Output:
./func_to_intf.go:30:14: cannot use fa (type AdderFunc) as type Adder
in argument to doAdd: AdderFunc does not implement Adder (missing add
method)
Questions
http.HandlerFunc(helloHandler) get a value of type http.Handler, since that's what http.Handle() expect, is that correct?
If yes, then means it convert a function into a value of an interface type, how did that happen?
Is this a built-in feature of go?
I did a test (as in func_to_intf.go above), and seems not.
Or, is http.HandlerFunc's special implementation achieve that?
#Update - Summary
(Though the answer(s) addressed the questions pretty well, but after reviewing & more testing, there are several other go features required to totally erase the original doubt, as following.)
Function type.
Function is value, and it has type.
Function type could be defined via type keyword on a function signature.
e.g type AdderFunc func(int, int) int
Type convertor T(v) on function.
Any function could be converted to a function type with the same signature, just via T(v), use function type name as T, and actual function as v.
Then when the new value is called, the actual function v is called.
e.g fa := AdderFunc(simpleAdd)
(this is blur to me before asking the question, and that's one of the main reason I was confused).

It is a simple type-conversion.
In Go you can define custom type besides structs. In this case, http.HandlerFunc is a function type, func(http.ResponseWriter,*http.Request). Since your function is of the same underlying type (signature) as the custom type, it can be converted to it.
Furthermore, code can define methods on custom type, no matter what underlying type it is, or whether it is a struct or not. In this case, http package defines ServeHTTP method on it, and of course, it just calls the function itself.
You can read the source code here: https://golang.org/src/net/http/server.go?s=58384:58444#L1936
As for the adder in your sample code, you can do the same: Define a method on AdderFunc.
func (a AdderFunc) add(x, y int) int {
return a(x, y)
}
Playground: https://play.golang.org/p/5mf_afHLQA2

http.HandlerFunc is a type that satisfy interface http.Handler by providing method http.ServeHTTP(ResponseWriter, *Request).
http.HandlerFunc(helloHandler) is a type conversion which convert types with same underlying base type but different method set.
You example working

Not special or built-in feature. Instead http.HandlerFunc is a type that implements the http.Handler interface. Have a look at its implementation which is quite nifty https://github.com/golang/go/blob/d3c3aaa61f7598f275f30fabd3749379fe0f2720/src/net/http/server.go#L1956

As the docs say:
The HandlerFunc type is an adapter to allow the use of ordinary functions as HTTP handlers. If f is a function with the appropriate signature, HandlerFunc(f) is a Handler that calls f.
So, it's not a function, but a wrapper type, declared as:
type HandlerFunc func(ResponseWriter, *Request)
But Go allows (and that's one of its greatest features, in my opinion) to make any newly declared type implement any possible interface just by defining the require method. So the type HandlerFunc implements the interface Handler by defining the method ServeHttp. The implementation just calls the wrapped function.

Related

Passing an arbitrary function as a parameter in Go

I'm trying to expand my knowledge of Go's function pointers, and I have a question about what is and is not possible with passing functions as parameters in Go.
Let's say that I want to write a decorator() function that can wrap any existing function. For simplicity, let's limit this to functions that accept exactly one parameter and return exactly one value.
If I write a decorator that accepts func(interface{}) interface{} as it's argument, it will implicitly work as long as that function I pass in also accepts/returns an interface{} type (see funcA).
My question is--is there a way to convert an existing function of type func(string) string to a type of func(interface{}) interface{} so that it can also be passed into a decorator function without just wrapping it in a new anonymous function (see funcB)?
package main
import (
"fmt"
)
func decorate(inner func(interface{}) interface{}, args interface{}) interface {} {
fmt.Println("Before inner")
result := inner(args)
fmt.Println("After inner")
return result
}
func funcA(arg interface{}) interface{} {
fmt.Print("Inside A, with arg: ")
fmt.Println(arg)
return "This is A's return value"
}
func funcB(arg string) string {
fmt.Print("Inside B, with arg: ")
fmt.Println(arg)
return "This is B's return value"
}
func main() {
// This one works. Output is:
//
// Before inner
// Inside A, with arg: (This is A's argument)
// After inner
// This is A's return value
//
fmt.Println(decorate(funcA, "(This is A's argument)"))
// This doesn't work. But can it?
//fmt.Println(decorate(funcB, "(This is B's argument)"))
}
This is not possible. One reason for that is the mechanics of passing parameters differ from function to function, and using an interface{} arg does not mean "accept anything". For example, a function taking a struct as an arg will receive each member of that struct, but a function taking an interface{} containing that struct will receive two words, one containing the type of the struct, and the other containing a pointer to it.
So, without using generics, the only way to implement this is by using an adapter function.
Use the reflect package to handle functions with arbitrary argument and result types.
func decorate(inner interface{}, args interface{}) interface{} {
fmt.Println("Before inner")
result := reflect.ValueOf(inner).Call([]reflect.Value{reflect.ValueOf(args)})
fmt.Println("After inner")
return result[0].Interface()
}
Run the code on the playground.
Like the decorate function in the question, the function in this answer assumes one argument and one result. The function must be modified to handle other function types.
The OP should consider the tradeoffs between the anonymous wrapper function proposed in the question and the use of the reflect package here. Calling the function through the reflect API is slower than calling the function through the anonymous wrapper. There's also a loss of type safety with the reflect API. The anonymous wrapper function adds verbosity.
For the record, with Go 1.18 and the introduction of generics, the decorator function becomes almost trivial.
You may declare a type constraint as such:
type UnaryFunc[T any] interface {
func(T) T
}
The constraint itself is parametrized with T to allow for unary functions that take and return arbitrary types.
In the decorate function you then instantiate the constraint with a type parameter. The signature becomes:
decorate[T any, F UnaryFunc[T]](inner F, arg T) T
Thanks to type inference, you can just pass concrete arguments to the function, and both T and F will be unambiguous.
Example alternatives without a named constraint:
// accept and return T
decorate[T any](inner func(T) T, arg T) T
// only return T
decorate[T any](inner func() T) T
// return T and error
decorate[T any](inner func(T) (T, error), arg T) (T, error)
// N-ary function
decorate[T, U any](inner func(T, U) (T, error), argt T, argu U) (T, error)
The obvious limitation is that the interface constraint UnaryFunc specifies only functions that take and return exactly one arg of type T. You can't do otherwise, because the type set of an interface constraint may include types which support the same operations — and calling with one arg is not compatible with calling with N args.
The full program:
package main
import (
"fmt"
)
type UnaryFunc[T any] interface {
func(T) T
}
func decorate[T any, F UnaryFunc[T]](inner F, arg T) T {
fmt.Println("before inner")
result := inner(arg)
fmt.Println("after inner")
return result
}
func funcA(arg int) int {
fmt.Println("inside A with:", arg)
return arg
}
func funcB(arg string) string {
fmt.Println("inside B with:", arg)
return arg
}
func main() {
// this works
decorate(funcA, 200)
// this also works
decorate(funcB, "Func B")
}
Playground: https://go.dev/play/p/3q01NiiWsve
is there a way to convert an existing function of type func(string) string to a type of func(interface{}) interface{} so that it can also be passed into a decorator function without just wrapping it in a new anonymous function (see funcB)?
No. It's that simple: No.

Can we use Type Assertion with interface method in Go?

I am trying to type assert in Go but error says struct doesn't implement interface method but I have clearly implemented method declared in interface.
This is the code I am trying to execute
package interfaces
import "fmt"
type Event interface {
Accept()
}
type Like struct {
}
// Like implement Accept method from Event interface
func (l *Like) Accept() {
fmt.Println("like accept")
}
func TypeAssertionExample() {
var l *Like = &Like{}
var e Event = l
_, f := e.(Like) // error even after Like implemented Accept method
fmt.Println(f)
}
Note that in addition to what Hymns for Disco suggested, we can modify your example (I've changed it to package main and func main for use on the Go Playground) so that instead of:
func (l *Like) Accept) {
// code
}
we have:
func (l Like) Accept() {
// code
}
and the code will then compile. But since e holds an instance of *Like, not one of Like, the test:
_, f := e.(Like)
fmt.Println(f)
prints false now. See the complete example here.
The question of when and whether to use pointer receivers is quite a basic one, and covered fairly well, though not explicitly, in the Go Tour. The FAQ has the same information in a more compact form, with some explicit details in a second section. See also Value receiver vs. pointer receiver.
Pointer types and non-pointer types aren't the same. You need to do this:
_, f := e.(*Like)
Notice the *, matching your variable declaration var l *Like.

Type func with interface parameter incompatible error

I have declared a new type func that takes any value that conforms to interface{}. However, when I invoke a function that has been passed as an argument (conforming to that type specification) I get an error.
Can somebody explain why this is the case? Below is the simplest example I could recreate the issue with.
type myfunc func(x interface{})
func a(num int) {
return
}
func b(f myfunc) {
f(2)
return
}
func main() {
b(a) // error: cannot use a (type func(int)) as type myfunc in argument to b
return
}
The concept you're looking for here is variance in the type system. Some type systems and types support covariance and contravariance, but Go's interfaces do not.
While an int can be passed to a function that expects interface{}, the same cannot be said about func(int) and func(interface{}), because interfaces do not behave covariantly.
If type x implements interface ii, it doesn't mean that func(x) implements func(ii).
What you could do is pass func(int) into a function that expects interface{}, so you could do
package main
import "fmt"
func foo(x interface{}) {
fmt.Println("foo", x)
}
func add2(n int) int {
return n + 2
}
func main() {
foo(add2)
}
Because func(int)int does implement interface{}.
In addition to the Wikipedia link at the top of the answer, this post provides more details about the different kinds of variance programming languages support. It mostly uses other languages, because variance is best demonstrated with languages that support inheritance.

Pointer receiver and Value receiver difference in implementation with Iris framework [duplicate]

This question already has answers here:
X does not implement Y (... method has a pointer receiver)
(4 answers)
Closed 3 years ago.
I am studying Iris framework recently. I encountered a question when I was implementing the Handler. Like following:
package controller
import "github.com/kataras/iris"
type Pages struct{
}
func (p *Pages) Serve(c *iris.Context) {
}
In order to use this controller, I implemented the following entry script:
package main
import (
"github.com/kataras/iris"
"web/controller"
)
func main(){
ctrl := controller.Pages{}
iris.Handle("GET", "/", ctrl)
iris.Listen(":8080")
}
But when I compiled the code, I got the following error message:
cannot use ctrl (type controllers.Pages) as type iris.Handler in argument to iris.Handle:
controllers.Pages does not implement iris.Handler (Serve method has pointer receiver)
After I changed the declaration to:
ctrl := &controller.Pages{}
Then the compiler passed with no complaint.
The question is: I thought the following statements are equal, since the GO compiler will do the conversion under the table:
type Pages struct {
}
func (p *Pages) goWithPointer() {
fmt.Println("goWithPointer")
}
func (p Pages) goWithValue() {
fmt.Println("goWithValue")
}
func main() {
p1 := Pages{}
p2 := &Pages{}
p1.goWithPointer()
p1.goWithValue()
p2.goWithPointer()
p2.goWithValue()
}
Why can't I use ctrl := controller.Pages{} as the parameter to iris.Handle(), instead of ctrl := &controller.Pages{} as the parameter to iris.Handle()?
Thank you for your time and sharing.
See Docs:
A type may have a method set associated with it. The method set of an
interface type is its interface. The method set of any other type T
consists of all methods declared with receiver type T. The method set
of the corresponding pointer type *T is the set of all methods
declared with receiver *T or T (that is, it also contains the method
set of T). Further rules apply to structs containing anonymous fields,
as described in the section on struct types. Any other type has an
empty method set. In a method set, each method must have a unique
non-blank method name.
And see: https://stackoverflow.com/a/33591156/6169399 :
If you have an interface I, and some or all of the methods in I's
method set are provided by methods with a receiver of *T (with the
remainder being provided by methods with a receiver of T), then *T
satisfies the interface I, but T doesn't. That is because *T's method
set includes T's, but not the other way around.
Using ctrl := Pages{} makes error:
cannot use ctrl (type Pages) as type Handler in argument to Handle:
Pages does not implement Handler (Serve method has pointer receiver)
Using ctrl := Pages{}needs:
func (p Pages) Serve() {
fmt.Println(p.i)
}
Iris Handler is an interface type. like this working sample (see comment):
package main
import "fmt"
type Handler interface {
Serve()
}
type Pages struct {
i int
}
func (p *Pages) Serve() {
fmt.Println(p.i)
}
func Handle(p Handler) {
p.Serve()
}
func main() {
// cannot use ctrl (type Pages) as type Handler in argument to Handle:
// Pages does not implement Handler (Serve method has pointer receiver)
//ctrl := Pages{}
ctrl := &Pages{101}
Handle(ctrl)
}
output:
101
According to https://godoc.org/github.com/kataras/iris#Handler. Iris Handler is an interface type.
GO performs implicit pointer-conversion on variables only, not on interfaces.

Golang: Where is an Interface method called?

I don't understand at which point an Interface method is being called. I'm looking at the following example from the Go Tour:
package main
import "fmt"
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}
func main() {
a := Person{"Arthur Dent", 42}
z := Person{"Zaphod Beeblebrox", 9001}
fmt.Println(a, z)
}
Problem:
I understand that the func (p Person) receives the String() method and that it returns the string I want to display. But the fmt.Println in the main() method has to call String() at some point, right?
I had a look at the source of fmt in godoc, but I still cannot figure it out!
Another example:
If I add my own interface, lets say Stringer2 with a method called String2() and then create a func (p Person) String2() {....}.
How does String() get executed by fmt.Println, but String2() not?
The value is passed to Println as an interface{}, and is checked if it satisfies the fmt.Stringer interface via a "type assertion" often in the form of a "type switch".
func IsStringer(i interface{}) {
switch s := i.(type) {
case fmt.Stringer:
fmt.Println("Person a has a String() method")
fmt.Println(s.String())
default:
fmt.Println("not a stringer")
}
// OR for a single type
if s, ok := i.(fmt.Stringer); ok {
fmt.Println("Person a has a String() method")
fmt.Println(s.String())
}
}
However, other methods may take precedence when printing from the fmt package. There are first checks for fmt.Formatter, fmt.GoStringer, error, and then finally fmt.Stringer.
The fmt package works with the interfaces it defines, in this case Stringer. It does not know of interfaces defined by you so it wouldn't know to call String2() even if you pass it a type that meets the Stringer2 interface.
Interfaces are a way to have common behavior between types. So if you create a function Foo(s Stringer2), Foo can simply call s.String2() confident that anything passed into it will have the function String2().
To go a bit deeper, fmt.Println takes interface{} types and then uses reflection to check if the given argument meets the Stringer interface to then call String().
Make sense?

Resources