Search code examples
gointerfacenetwork-programmingmicroservices

Extend an interface method in a non-local package


Trying to create a microservice within Go, I have a package network to take care of getting the bytes and converting to a particular request:

package network

type Request interface {
}

type RequestA struct {
a int
}

type RequestB struct {
b string
}

func GetRequestFromBytes(conn net.Conn) Request {
buf := make([]byte, 100)
_, _ := conn.Read(buf)
switch buf[0] {
case 0:
    // convert bytes into RequestA
    requestA = RequestAFromBytes(buf[1:])
    return requestA
case 1:
    requestB = RequestBFromBytes(buf[1:])
    return requestB
}}

Now in the main, I want to handle the request.

package main
import (
    "network"
)

(ra *RequestA) Handle() {
// handle here
}

(rb *RequestB) Handle() {
// handle
}

func main() {
    // get conn here
    req = GetRequestFromBytes(conn)
    req.Handle()
}

However, Golang does not allow RequestA/RequestB classes to be extended in the main package. Two solutions I found online were type aliasing/embedding, but in both it looks like we'll have to handle by finding the specific type of the request at runtime. This necessitates a switch/if statement in both network and main packages, which duplicates code in both.

The simplest solution would be to move the switch statement into package main, where we determine the type of the request and then handle it, but then package main would have to deal with raw bytes, which I'd like to avoid. The responsibility of finding the request type and sending it 'upwards' should rest with the network package.

Is there a simple idiomatic Go way to solve this?


Solution

  • Use a type switch in the main package:

    switch req := network.GetRequestFromBytes(conn).(type) {
    case *network.RequestA:
       // handle here, req has type *RequestA in this branch
    case *network.RequestB:
       // handle here, req has type *RequestB in this branch
    default:
       // handle unknown request type
    }
    

    This avoids encoding knowledge of the protocol bytes in the main package.

    Because the question specifies that parsing code is in the network package and handler code is in the main package, it's not possible to avoid updating the code in two packages when a new request type is added. Even if the language supported the feature proposed in the question, it would still be necessary to update two packages when a new request type is added.