[+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/CAEkBMfE-BvA6JyZfuUE6ztSOc6b7xzZubXNs3-wdObPNx1%2BNNQ%40mail.gmail.com.