[+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.

Reply via email to