Golang: Autocomplete missing interface methods - go

I am currently working on a go project where I define an interface to use in another file. My workflow works but I'm confused at either why there doesn't seem to be any "auto-complete" for protocols or why I cannot find it, I am using VSCode.
First of all, I am not fluent in go at all so if I misuse the term "object" for example that's because I don't know any better.
Let's say the interface looks like that:
type TestInterface interface {
Function1()
}
and my function to pass an object of that interface to looks like that
func Start(obj TestInterface) {
...
Now, in order to define a type that I can construct an object of, I do
type TestInterfaceType int
and because I have to conform to the interface defined, I need to apply these functions to my "new" type
func (e TestInterfaceType) Function1() {
fmt.Println("Test")
}
I am then able to construct an object
var testInterfaceTypeObject TestInterface
testInterfaceTypeObject = TestInterfaceType(1)
and passing that object to my Start() function above which expects a type of that interface works fine since the object of my "new type" has the functions defined that are defined on the interface.
Everything until here works as I have expected, or at least it works for me.
Now if I add another function to the TestInterface but I do not apply that new function to my TestInterfaceType, I see an error coming up that is InvalidIfaceAssign:
InvalidIfaceAssign occurs when a value of type T is used as an
interface, but T does not implement a method of the expected
interface.
I understand why this is happening, I also have to do the func (e TestInterfaceType) ... for my new function but here is my question:
Is there a way to automatically generate empty mock functions for the missing functions? In Java for example, the IDE offers me to add the missing functions (without functionality of course, but at least they are there, ready for me to write logic into them)?
In other words, once I add Function2() to TestInterface, can I make it automatically do
func (e TestInterfaceType) Function2() {
}
wherever I use that interface?

Related

Unable to work with interface imported from another pkg, says method is missing but its there

I'm unable to work with an interface imported from another package and not sure what I should do. Example code:
var inner types.TxData // <-- interface imported from types package
inner = &InternalTx{
ChainId: (*big.Int)(dec.ChainID),
Data: *dec.Data,
}
Out of all the methods listed in the interface, 1 method is not accepted:
func (tx *InternalTx) accessList() types.AccessList { return nil }
Go complains that InternalTx does not implement accessList() to satisfy types.TxData interface, but if i capitalise accessList() to Accesslist() then I get another complaint stating that :
have AccessList() types.AccessList
want accessList() types.AccessList
So i'm very confused what I need to do here?
Edit:
I've implemented also the following based on recent suggestion:
type TxData struct {
types.TxData
}
var inner TxData
internalTx := &InternalTx{
ChainId: (*big.Int)(dec.ChainID),
Data: *dec.Data,
}
inner = TxData{TxData: internalTx}
Issue still persists.
If an interface is declared with an unexported method (such as accessList), then you cannot implement that interface in another package, because that name is not exported. This is a common way to force you to use implementations in the original package.
One way to deal with this is to embed that interface, and then delegate functionality to an implementation of it:
type TxData struct {
types.TxData
}
someImplementation:=// Get an implementation of types.TxData
inner:=TxData{TxData: someImplementation}
This will use the accessList of someImplementation.

Override interface's function callback arguments

I am using a package that has a Router interface, and I have created my own app-specific Router interface that wraps the third party package.
Everything is working well, however one of the methods is throwing a compilation error:
controllers/auth.go:52:17: cannot use func literal (type func(router.Router)) as type func(chi.Router) in argument to c.router.Group
This is the interface of the third party package (chi):
type Router interface {
// ...
// Group adds a new inline-Router along the current routing
// path, with a fresh middleware stack for the inline-Router.
Group(fn func(r Router)) Router
// ...
}
This is my wrapper interface:
type Router interface {
chi.Router
// Custom methods...
}
My usage of the Group function is like so:
type AuthController struct {
router router.Router
// ...
}
func (c *AuthController) SetRoutes() {
c.router.Group(func(r router.Router) {
r.Use(middleware.Anyone)
r.Post("/auth/register", c.Register)
r.Post("/auth/login", c.Authenticate)
r.Post("/auth/token/refresh", c.RefreshToken)
})
c.router.Group(func(r router.Router) {
r.Use(middleware.Authorized)
r.Get("/auth/ping", c.Ping)
r.Post("/auth/logout", c.Logout)
})
}
Why is it screaming at my function callbacks argument type? My wrapper router.Router implements the chi.Router interface, so it should work fine shouldn't it? Am I misunderstanding how Go works here?
I can see how this can be confusing so I will try to break it down. You have this method:
Group(fn func(r Router)) Router
This method takes a function as a parameter. That function must have a specific signature:
func(r Router)
That is, it takes a single argument of type chi.Router and has no return values. However, when you call it:
c.router.Group(func(r router.Router) { /***/ }
You're passing in a function of the wrong signature; your function signature is:
func(r router.Router)
That's not the signature required by the method you're calling, so it won't compile. It doesn't matter if router.Router implements chi.Router; the parameter (a func(router.Router)) passed is not of the expected type (a func(chi.Router)).
This may seem silly at first - after all, any router.Router must implement chi.Router. But, think about it: that method, Group, is expecting to receive a function, to which it can pass any chi.Router. That means it can pass a chi.Router which does not implement router.Router. If it were to accept your function, it would break type safety, and what in Go is meant to be a compile-time error (the error you're getting, in fact) would become a run-time error. Basically, by passing a function with a different (and more strict) argument type, you're expecting a guarantee which that method never offered.
The parameter types aren't the same, so the function type doesn't match what's expected, even though your interface includes the interface from the other package (the type has to match exactly). You need to have your functions take a chi.router and then use a type assertion, i.e., myRouter := r.(Router), to convert to your type.

Composition combining data and functions with interfaces and structs

I'm wondering if this is something that's done in Go or if I'm thinking about it all wrong: composing type x interface and type x struct so my interface methods have access to specific data too:
The C programmer in my wants to do this:
type PluginHandler interface {
onLoad()
pm *PluginManager
}
func (ph PluginHandler) onLoad() {
pm.DoSomething()
}
There I have an interface defined with a function, but also some data I want to pass to those functions but this is a syntax error.
So is this something that's doable in Go through some other method or am I just thinking about the problem wrong?
You have defined onLoad incorrectly. You cannot define a function directly on interface type.
Once you have an interface, you need another type to implement methods specified in the interface. For example, if another type implements onLoad method, they automatically (implicitly) implement the interface PluginHandler.
The other thing you need to do is change the interface function type to accept the required data:
type PluginHandler interface {
onLoad(*PluginManager)
}
struct SomeType {
// ...
}
func (s SomeType) onLoad(pm *PluginManager) { // SomeType now implements
pm.DoSomething() // PluginHandler interface.
}
This way, you get to inject whichever PluginManager required by PluginHandler.
Also, you can use SomeType as a PluginHandler type whereever required.
func someFuntion(ph PluginHandler) {
// ...
ph.onLoad(pm)
// ...
}
Can be called with an input argument of type SomeType:
s := SomeType{}
someFunction(s)
TL;DR; There is no direct translation to Go.
Long answer:
Go interfaces are only methods.
Go structs are only data (with the possibility of receiver methods).
You can reference, and even embed interfaces within structs:
type Frobnicator interface {
Frobnicate() error
}
type Widget struct {
Frobnicator
WidgetName string
}
But that's not really what you're talking about.
The best answer to your dilema is, I believe: Take a step back. You're focusing on the trees, and you need to look at the forest. Go takes a different approach than C, or classical OO languages like C++ and Java.
Look at the general problem to be solved, and find solutions to that in Go. This can be a painful process (I can say from experience), but it's really the only way to learn the new way of thinking.
Just for the record, you can add extra methods to an existing type, by introducing another (indirection) type as:
type HandlerManager PluginManager
func (x *HandlerManager) onLoad() {
((*PluginManager)(x)).DoSomething()
}
And if you need to go with a more generic solution, a combination of Adapter & Strategy patterns could do:
type PluginHandlerAdapter struct{ _onLoad func() }
func (x *PluginHandlerAdapter) onLoad() {
x._onLoad()
}
Used like (public/private access ignored):
type PluginManager struct {
PluginHandlerAdapter
}
func NewPluginManager() *PluginManager {
res := new(PluginManager)
res._onLoad = res.DoSomething
return res
}

Golang code structuring

Is it worth to group methods in structs:
For example:
type UserManager struct {
DB *sql.DB
}
func (m UserManager) Insert (u User) error {...}
func (m UserManager) Delete (u User) error {...}
...
Or is it simpler support just separate functions.
func InsertUser (u User, db *sql.DB) error {...}
While second approach looks simpler at first, in future this way, there may be to many functions in package. Should I make separate package for every domain aggregate? In examples, I've seen so far, there is just model package.
I've been working mainly with OO languages so need some advice for go best practices here.
Your second suggestion is not good go code! Why? Because in the best case a function should take interfaces as an input.
So a InsertUserfunction should look something like that and it would combine your first with your second suggestion:
type Inserter interface {
Insert(User)error
}
func InsertUser(i Inserter) error {...}
In that case testing of your function is easy, because you can easy mock the inserter.
Either, or neither - it really doesn't matter in my opinion because the idiomatic approach would be to organize these concepts using interfaces:
package user
type User ...
type Inserter interface { Insert(User) error }
type Deleter interface { Delete(User) error }
type Manager interface { Inserter, Deleter } // bloated interface
User in this case is probably a concrete row type like in your example, but one could make the case for making it too into an interface that doesn't mention those types.
If you write functions that reference these interfaces, then you can quickly glue together using embedding & promoted fields.
In your case it's obvious that sticking to the first implementation style is much simpler:
type userManager struct { ... }
func (userManager) Insert(u User) error { ... }
func (userManager) Delete(u User) error { ... }
userManager is a private type, so it can be changed without concern, as long as it keeps satisfying the public interfaces.
Keeping the interfaces decoupled from the implementation makes it much easier to make them narrow, so instead of just having a "user manager" or something, you can find out which interfaces you really need for the tasks. Incidentally, this approach has the nice property that it fits well with the object capability model, which helps to simplify things like role based access control.

Golang monkey patching

I understand that if go code is structured such that it's programmed to interfaces, it's trivial to mock; however, I'm working with a code base that I cannot change (that is not mine) and this is not the case.
This code base is heavily interconnected and nothing is programmed to an interface, only structs, so no dependency injection.
The structs, themselves, only contain other structs, so I can't mock out that way either. I don't believe that I can do anything about methods, and the few functions that exist are not variables, so there's no way that I know of to swap them out. Inheritance isn't a thing in golang, so that's a no go as well.
In scripting languages like python, we can modify the objects at runtime, aka monkey patch. Is there something comparable that I can do in golang? Trying to figure out some way to test/benchmark without touching the underlying code.
When I have run into this situation my approach is to use my own interface as a wrapper which allows mocking in tests. For example.
type MyInterface interface {
DoSomething(i int) error
DoSomethingElse() ([]int, error)
}
type Concrete struct {
client *somepackage.Client
}
func (c *Concrete) DoSomething(i int) error {
return c.client.DoSomething(i)
}
func (c *Concrete) DoSomethingElse() ([]int, error) {
return c.client.DoSomethingElse()
}
Now you can mock the Concrete in the same way you would mock somepackage.Client if it too were an interface.
As pointed out in the comments below by #elithrar, you can embed the type you want to mock so you are only forced to add methods which need mocking. For example:
type Concrete struct {
*somepackage.Client
}
When done like that, additional methods like DoSomethingNotNeedingMocking could be called directly on Concrete without having to add it to the interface / mock it out.
There is an available monkey patching library for Go. It only works for Intel/AMD systems (targeting OSX and Ubuntu in particular).
Depending on the situation, you can apply the "Dependency Inversion Principle" and leverage Go's implicit interfaces.
To do this, you define an interface of your requirements in the package with the usage (as opposed to defining what you provide in the package that implements it; like you might in Java).
Then you can test your code in isolation from the dependency.
Typical object with a struct dependency:
// Object that relies on a struct
type ObjectUnderTestBefore struct {
db *sql.DB
}
func (o *ObjectUnderTestBefore) Delete() error {
o.db.Exec("DELETE FROM sometable")
}
Apply Dependency Inversion Principle (with implicit interface)
// subset of sql.DB which defines our "requirements"
type dbExec interface {
Exec(query string, args ...interface{}) (sql.Result, error)
}
// Same object with it's requirement defined as an local interface
type ObjectUnderTestWithDIP struct {
// *sql.DB will implicitly implement this interface
db dbExec
}
func (o *ObjectUnderTestWithDIP) Delete() error {
o.db.Exec("DELETE FROM sometable")
}

Resources