Is there any way to overwrite the original struct function?

I have three packages: router controller custom

controller imports a default structure from custom, if in the controller package I create a function that already exists in custom then ServeHTTP from custom should execute the controller function and not the original one.


package router

import "project/controller"
router.Handler("GET", "/service", &controller.Service{})
package controller

import "project/custom"

type Service struct{ custom.PageController }

func (c *Service) Sample() {
	fmt.Println("from controller")
}
package custom

type PageController struct {}

func (c *PageController) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c.Sample()
	w.Write([]byte("This is my page"))
}

func (c *PageController) Sample(){
	fmt.Println("from custom")
}

With the above explained my goal is that the output will be:
"from controller"

But currently the output is:
"from custom"

In this example it works for me

Sorry my example is a bit different; I’ll che better

Hello,

in this example I used interface to achieve the goal.

This is what I do usually when I need to do something similar to your needs

1 Like

Hi @Willy,

Your code cannot compile because there is no Controller type for method func (c *Controller) Sample(), did you mean func (c *PageController) Sample()?

I condensed all packages into one for simplicity - Playground link

package main

import "fmt"

type PageController struct{}

func (c *PageController) Sample() {
	fmt.Println("from custom")
}

type Service struct {
	PageController
}

func (c *Service) Sample() {
	fmt.Println("from controller")
}

func main() {
	s := Service{}
	s.Sample()                // "from controller"
	s.PageController.Sample() // "from custom"

	p := PageController{}
	p.Sample() // "from custom"
}

s.Sample() always calls func (c *Service) Sample(). In order to reach method Sample() of the embedded field PageController, you need to make the calling path explicit: s.PageController.Sample().

@Massimo.Costa’s example with interfaces is a good way of implementing dynamic behavior of this kind.

1 Like

@christophberger @Massimo.Costa

Thanks to your answers I could get an idea of what I had to improve in my code, apparently if I want to overwrite Sample() I must first overwrite ServeHTTP(w http.ResponseWriter, r *http.Request) in the controller package but that would then move away from my goal, or of course I could also use some of your suggestions but I have read that the way of working I was looking for is similar to inheritance in other languages and that Go should not be used that way, so I will change my project design.

But now then I would like to know your opinion of when it is better to use these two options:
router.Handler("GET", "/service", &controller.Service{}).
router.GET("/service", othercontroller.Service()).

As you can see the difference is that the second one receives a function from the othercontroller package and the first one a struct and both comply with the signature:
ServeHTTP(w http.ResponseWriter, r *http.Request).

My question in case it wasn’t understood boils down to when should I use a function and a struct to handle client requests.

1 Like

to be really honest I don’t have a strong opinion about that.

Usually for non-trivial apps/services I use go-kit for the business logic and go-chi as HTTP router, in that case both toolkits impose some constraint.

A “nice” thing about go-kit (no just one) is that it enforces the use of Dependency Injection with interfaces.

I don’t think there are strict rules for that. It depends largely on the context and maybe a bit on your prefererences.