If you're new to Go, beware of one thing when returning interface values which are implemented by pointers. An interface value can be nil (i.e. the zero value of interface: no type and no value); or it can contain a concrete value a concrete pointer type - where the concrete value itself is nil. These two cases are distinct.
https://go.dev/play/p/cYJralfkYf6 On Monday, 20 June 2022 at 19:44:01 UTC+1 axel.wa...@googlemail.com wrote: > [+golang-nuts again. Please don't respond off-list, so anyone can benefit > from the discussion] > > On Mon, Jun 20, 2022 at 8:32 PM Deividas Petraitis < > h...@deividaspetraitis.lt> wrote: > >> Thank you for reply, it was really helpful! I wish groups would allow to >> edit the title. >> According to he FAQ it seems like there should be some other ways to >> achieve what I am trying to accomplish here: >> > Programmers who want covariant result types are often trying to express >> a type hierarchy through interfaces. In Go it's more natural to have a >> clean separation between interface and implementation. >> I tried to google based on this keyword and found few interesting >> articles why covariance return types would be difficult to achieve, but not >> how to solve this problem using Go constructs. >> In your opinion is my solution is right one for this problem? If not >> could you please give me few more ideas/hints. :) >> > > You have to change the return type from `*FailingRoute` to `mux.Route`, so > the types match. > > >> >> On Friday, 17 June 2022 at 22:22:12 UTC+3 axel.wa...@googlemail.com >> wrote: >> >>> This is called "covariance" and the FAQ attempts to answer this question: >>> https://go.dev/doc/faq#covariant_types >>> Personally, I'm not fully convinced Go shouldn't have co/contravariant >>> `func`, but I feel this has been ingrained for over ten years now and it's >>> unlikely to change. >>> >>> On Fri, Jun 17, 2022 at 9:11 PM Deividas Petraitis < >>> h...@deividaspetraitis.lt> wrote: >>> >>>> Today while working on my side project I have encountered interesting >>>> issue and despite I was able to overcome it I have realised that I might >>>> be >>>> missing some import concepts about Go. >>>> Let me share example code to demostrate the issue I am referring to: >>>> >>>> ```go >>>> package main >>>> >>>> import ( >>>> "net/http" >>>> >>>> "github.com/gorilla/mux" >>>> ) >>>> >>>> func main() { >>>> // We can pass GorillaRouter as Router, because it implement >>>> required methods >>>> _ = ServerHandler{ >>>> router: NewGorillaRouter(), >>>> } >>>> >>>> // We can not pass FailingRouter as Router, because of: >>>> // cannot use FailingRouter{} (value of type FailingRouter) as type >>>> Router in struct literal: >>>> // FailingRouter does not implement Router (wrong type for >>>> HandleFunc method) >>>> // have HandleFunc(path string, handler >>>> func(http.ResponseWriter, *http.Request)) *FailingRoute >>>> // want HandleFunc(path string, handler >>>> func(http.ResponseWriter, *http.Request)) Route >>>> _ = ServerHandler{ >>>> router: FailingRouter{}, >>>> } >>>> } >>>> >>>> type ServerHandler struct { >>>> router Router >>>> } >>>> >>>> type Router interface { >>>> HandleFunc(path string, handler func(http.ResponseWriter, >>>> *http.Request)) Route >>>> } >>>> >>>> type Route interface { >>>> Methods(methods ...string) Route >>>> } >>>> >>>> func NewGorillaRouter() *GorillaRouter { >>>> return &GorillaRouter{ >>>> router: mux.NewRouter(), >>>> } >>>> } >>>> >>>> type GorillaRouter struct { >>>> router *mux.Router >>>> } >>>> >>>> func (gr *GorillaRouter) HandleFunc(path string, handler >>>> func(http.ResponseWriter, *http.Request)) Route { >>>> return &GorillaRoute{ >>>> route: gr.router.HandleFunc(path, handler), >>>> } >>>> } >>>> >>>> type GorillaRoute struct { >>>> route *mux.Route >>>> } >>>> >>>> func (r *GorillaRoute) Methods(methods ...string) Route { >>>> r.route = r.route.Methods(methods...) >>>> return r >>>> } >>>> >>>> type FailingRouter struct{} >>>> >>>> func (fr *FailingRouter) HandleFunc(path string, handler >>>> func(http.ResponseWriter, *http.Request)) *FailingRoute { >>>> return &FailingRoute{} >>>> } >>>> >>>> type FailingRoute struct{} >>>> >>>> func (r *FailingRoute) Methods(methods ...string) *FailingRoute { >>>> return r >>>> } >>>> ``` >>>> >>>> For convienence you can find soure code from above and run it here: >>>> https://go.dev/play/p/M6N48FeegND >>>> Now when code and context is clear question is following: why in >>>> `FailingRouter` assignment compiler is not happy while in `GorillaRouter` >>>> it is happy? >>>> >>>> Or to rephrase, why assigning concrete implementation to a parameter of >>>> interface type is accepted: >>>> >>>> ```go >>>> type ServerHandler struct { >>>> router Router // assigning GorillaRouter to router is accepted >>>> } >>>> ``` >>>> >>>> but vice versa is not and throws an error: >>>> >>>> ```go >>>> HandleFunc(path string, handler func(http.ResponseWriter, >>>> *http.Request)) *FailingRoute // returning concrete that implements Router >>>> is not allowed >>>> ``` >>>> Is my approach ( `GorillaRouter` ) correct solution for this problem? >>>> >>>> P.S. Sorry about the title, I am still not sure is it right for this >>>> problem description. >>>> >>>> -- >>>> 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. >>>> To view this discussion on the web visit >>>> https://groups.google.com/d/msgid/golang-nuts/fdc03ca3-f899-455a-8b7c-319c646f483an%40googlegroups.com >>>> >>>> <https://groups.google.com/d/msgid/golang-nuts/fdc03ca3-f899-455a-8b7c-319c646f483an%40googlegroups.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>> -- 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+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/5855c6fb-5c6c-4f0c-b440-0955ce49e737n%40googlegroups.com.