Deprecation
The supported way of marking functions as deprecated is something like this:
type MyStruct struct {
}
// MyFunc returns hello
// Deprecated: Use YourFunc
func (m MyStruct) MyFunc() string {
return "hello"
}
Modern IDEs will highlight any usages of this function and linters might also raise warnings (I haven't personally checked this)
Accept interfaces. Return structs.
A popular best practise is "Accept interfaces. Return structs." - which tends to encourage SOLID design in software.
However, the following code - which follows this best practise - conceals the deprecation warning:
// MyInterface specifies a single function that we require from a dependency
type MyInterface interface {
MyFunc() string
}
func main() {
var v MyInterface
v = MyStruct{}
v.MyFunc()
}
Question
Is there a solution to this problem?
If I were, for example, a library maintainer: how can I ensure that my deprecation warnings are seen by users of the library who are also following best practises and defining their own dependency interfaces.
That seems logical since the method of the interface has not been deprecated. Adding the Deprecated: line to the interface function might help in this case (didn't test, since VSCode doesn't do this yet).
// MyInterface specifies a single function that we require from a dependency
type MyInterface interface {
// Deprecated: use YourFunc
MyFunc() string
}
In this case, because the interface only has 1 function you should deprecated the whole thing. Which I know is supported by godoc/pkg.go.dev, take Queryer for example.
// MyInterface specifies a single function that we require from a dependency
// Deprecated: use YourInterface
type MyInterface interface {
MyFunc() string
}
Related
I'm writing a piece of code that relies on some implementation.
I want to decouple the implementation from my code, and make the implementation as independent as possible.
I thought of achieving this approach by using interfaces instead of concrete types, like so:
package mypackage
type MyType interface {
Title() string
Price() int
}
type TypeGetter interface {
GetType() MyType
}
func MyHandler(tg TypeGetter) {
t := tg.GetType()
fmt.Printf("Title: %s, Price: %d", t.Title(), t.Price())
}
And an implementation might be something like this:
package external
// CustomType implicitly implements the MyType interface
type CustomType struct {
title string
price int
}
func (t CustomType) Title() string { return t.title }
func (t CustomType) Price() int { return t.price }
// CustomTypeGetter implicitly implements the TypeGetter interface. Or is it???
type CustomTypeGetter struct {
}
func (g CustomTypeGetter) GetType() CustomType {
return CustomType{"Hello", 42}
}
Then, the code would do something like this:
package main
import "mypackage"
import "external"
func main() {
tg := external.CustomTypeGetter{}
mypackage.MyHandler(tg) // <--- the compiler does not like this
}
I hope the example speaks for itself: I have no coupling between "mypackage" and the "external" package, which may be replaced, substituted my mocks for testing, etc.
The problem: the compiler complains that the call to MyHandler has an object that implements:
func GetType() CustomType, instead of:
func GetType() MyType
The only solution I found is to move the interface declarations (MyType and TypeGetter) to a third package, and then both "mypackage" and "external" packages can use it.
But I want to avoid that.
Isn't Go's concept of implicit implementation of interfaces contradict the idea of a third common package?
Is there a way to implement such thing, without binding the two packages together?
Isn't Go's concept of implicit implementation of interfaces contradict the idea of a third common package?
I think it does. Go authors introduced an implicit interface implementation to eliminate unnecessary dependencies between packages. That works well for simple interfaces like io.Reader, but you cannot apply it everywhere.
One of the language creators, Rob Pike, says that the non-declarative satisfaction of interfaces is not the essential part of the idea behind interfaces in Go. It's a nice feature, but not all elements of the language are practical or possible to use every time.
For complex interfaces, you need to import a package where the interface is defined. For example, if you want to implement an SQL driver that works with the sql package from the standard library, you must import the sql/driver package.
I would recommend not introducing interfaces at the beginning of your project. Usually, it leads to situations where you need to solve artificial problems like rewriting the interface each time you updates your understanding of the domain model. It is hard to come up with a good abstraction from the first attempt, and, in many cases, it is unnecessary, in my opinion.
I need to query external source for products. I don't care how the external sources store the data (db, file, network). I just need a "product" type. So it's either I define a Product type, forcing the external implementations to import and use it, or the Go way - define a Product interface and let the implementations implicitly implement this interface. Which apparently doesn't work
I see two loosely related goals here:
Define an interface to swap implementations of the product source.
A package that implements the product source should not import the package that defines the interface.
From my experience, I would recommend doing point 1 only when you have at least one working implementation of the product source service.
Point 2 is not always possible to achieve, and it is fine; please see the example from the standard Go library above.
P.S.
Please, consider not creating Product interface. While it does makes sense to come up with the PorductSource interface eventually, Product is most probably just a set of data; struct is a perfect way to represent such information. Please, see this very relevant code smaple and this article for inspiration.
The problem with your approach is that you want someone to implement an interface that refers to your type (MyType). This obviously cannot be done without the implementation referring to your type. This is the only thing that prevents the above code from working.
If you get rid of the MyType:
type TypeGetter interface {
GetType() interface {
Title() string
Price() int
}
}
And the implementation:
func (g CustomTypeGetter) GetType() interface {
Title() string
Price() int
} {
return CustomType{"Hello", 42}
}
Then this code will work:
func main() {
tg := external.CustomTypeGetter{}
mypackage.MyHandler(tg)
}
Yes, this requires repetition, but only because you don't want an unknown / future implementation to refer to your type (to not depend on it).
In this case you may change MyHandler() to take a value of type MyType (get rid of the "factory"):
func MyHandler(t MyType) {
fmt.Printf("Title: %s, Price: %d", t.Title(), t.Price())
}
And any value that implements MyType may be passed. Add a "factory" to the external package:
func NewCustomType(title string, price int) CustomType {
return CustomType{
title: title,
price: price,
}
}
And use it like this:
func main() {
t := external.NewCustomType("title", 1)
mypackage.MyHandler(t)
}
If you truly require the factory pattern, then yes, creating a 3rd package that will hold MyType is the way to go. Then both your app and the implementations may refer to this 3rd package.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
OK, I'm not quite getting it....
I have 2 modules I crafted with identical functions (in different files of course):
package mod1
func MyFunc() string {
return "mod1.Myfunc"
}
func Func2() string {
return "mod1.Func2"
}
package mod2
func MyFunc() string {
return "mod2.MyFunc"
}
func Func2() string {
return "mod2.Func2"
}
I have an interface defined correctly, (I think) in a third package:
package types
type MyType interface {
MyFunc() string
Func2() string
}
I have code which can pick whether I want to use mod1 or mod2, but I'm not quite understanding what I should have this code return:
func mypicker() ????{
}
Then in main, I want to somehow call either mod1.MyFunc() or mod2.MyFunc() based on
mypicker, without knowing which it is.... something like this:
func main() {
p := mypicker()
fmt.Print(p.MyFunc())
// and later
fmt.Print(p.Func2())
}
I read that interfaces are like void *, but clearly I'm not getting the complete picture.
Pointers to docs, code, anything useful would be great.
Interfaces should be used with types, not just plain functions. You can start by reading the Tour of Go sequence on interfaces. Here's an example close to your question's original code:
Given the interface:
type MyType interface {
MyFunc() string
Func2() string
}
You'd have a type:
type MyType1 struct{}
func (mt MyType1) MyFunc() string {
return "MyType1.MyFunc"
}
func (mt MyType1) Func2() string {
return "MyType1.Func2"
}
And similarly:
type MyType2 struct{}
func (mt MyType2) MyFunc() string {
return "MyType2.MyFunc"
}
func (mt MyType2) Func2() string {
return "MyType2.Func2"
}
And now, if you have some function that takes your MyType interface:
func Foo(m MyType) {
fmt.Println(m.Func2())
fmt.Println(m.MyFunc())
}
You could call it with either of your types that implements that interface:
m1 := MyType1{}
Foo(m1)
m2 := MyType2{}
Foo(m2)
Here's a Go Playground link where you can try this in action.
As for "picking a type", perhaps you mean something like this:
var mi MyType
if (... some condition ...) {
mi = m1
} else {
mi = m2
}
// Now you can do with mi whatever its interfaces permits,
// like calling mi.Func2(), etc.
Regarding the "picking one of two packages" part of the question:
Interfaces are implemented by types; they're orthogonal to packages and modules. In other words, an interface and types that implement it can all be in the same package, or in different packages, or in different modules.
You have to be careful with terminology. Go modules and Go packages are very different, even though both can be contained by directories. Basically, a directory is a package if it has at least one Go file in it and no go.mod file. If a directory has a go.mod file in it then it's recognized as a module. Generally, a whole project can be a single module with the go.mod file at the root of the project and that's sufficient. Assuming this is your case, move forward thinking that every sub-directory is just a package within that single module.
An interface doesn't really have to do with modules or packages, it has to do with types. The reason being is that an interface defines behavior, meaning it defines what methods are required for a type to accurately implement that interface. In your case, you defined both functions declared in your interface BUT they are NOT METHODS because they are top-level functions only attached to the package. In order for a function to be a method, it must be "attached" to a type. Then, that type becomes a valid implementation of that interface.
This...
package mod1
func MyFunc() string {
return "mod1.Myfunc"
}
func Func2() string {
return "mod1.Func2"
}
Needs to become this...
package mod1
type MyTypeImpl struct {}
func (m MyTypeImpl) MyFunc() string {
return "mod1.Myfunc"
}
func (m MyTypeImpl) Func2() string {
return "mod1.Func2"
}
The naming could be improved greatly but the point is that the above function declaration syntax is how you "attach" a function to a type, making it a method, which allows that MyTypeImpl struct to now be a valid implementation of your MyType interface.
Now you can call the interface methods without regards to which underlying type is actually the implementation:
var iType MyType
iType = MyTypeImpl{}
iType.MyFunc()
Notice that in that last line, it does not matter that we used MyTypeImpl to implement the interface. Once the implementation is assigned to a variable with the interface type, we just work with the interface and forget the underlying implementation. When we call iType.MyFunc(), Go will call the proper method from the underlying implementation.
If we had 100 different structs that implemented the MyType interface as MyTypeImpl does, they could all work for the right side of that iType = MyTypeImpl{} line. That's the point of an interface, to define it once and then use it without regard to what underlying struct is actually implementing it.
I understand a bit a go and to certain extend understand interface as well(like how I do ducktyping in ruby)
But reading the interface definition https://github.com/golang/go/wiki/CodeReviewComments
I'm clueless what is trying to convey.
1st: I did not understood the comment.
Go interfaces generally belong in the package that uses values of the interface type, not the package that implements those values.
2nd: I do not understand this
Do not define interfaces on the implementor side of an API "for mocking"; instead, design the API so that it can be tested using the public API of the real implementation.
3rd: I do not understand the example
Do not define interfaces before they are used: without a realistic example of usage, it is too difficult to see whether an interface is even necessary, let alone what methods it ought to contain.
package consumer // consumer.go
type Thinger interface { Thing() bool }
func Foo(t Thinger) string { ..... }
package consumer // consumer_test.go
type fakeThinger struct{ … }
func (t fakeThinger) Thing() bool { … }
if Foo(fakeThinger{…}) == "x" { ... }
// DO NOT DO IT!!!
package producer
type Thinger interface { Thing() bool }
type defaultThinger struct{ … }
func (t defaultThinger) Thing() bool { … }
func NewThinger() Thinger { return defaultThinger{ … } }
package producer
type Thinger struct{ … }
func (t Thinger) Thing() bool { … }
func NewThinger() Thinger { return Thinger{ … } }
Can someone explain in plain and easier word the 3 things above.
Forget analogies with other languages for the moment. Think of an interface like a contract - a set of requirements for the function that uses it.
Say I define a function MakeNoise which needs to know the sound of the thing passed in, but otherwise doesn't care about it. Code below is all together, but imagine this in two separate packages - one for concrete types and one for MakeNoise.
The MakeNoise function could take a specific type, but this limits it somewhat, might make testing harder etc, so often you might want it instead to define what it needs the type to do - in this case it just needs something with a Sound() method to call, other than that it doesn't care.
Now on the Cat/Dog side, you might not care about MakeNoise, or even know about it yet, your animals should be defined separately and not care about any interfaces they conform with - those interfaces might not even have been written yet.
So the Wiki is just saying that whoever writes MakeNoise should care about what it requires and put that in an interface, but whoever writes Cat/Dog should not care, and the interface should sit with MakeNoise, not with Cat/Dog. This means later someone might come and write a Giraffe in another package, and it can still be used with MakeNoise.
The interface is a requirement, not a promise.
https://play.golang.org/p/4r1wiXokKMb
// Here are some types which share one function.
// They might have other functions too
package main
type Cat struct {}
func (d Cat) Sound() string {
return "miao"
}
type Dog struct {}
func (d Dog) Sound() string {
return "woof"
}
func main() {
cat := Cat{}
dog := Dog{}
MakeNoise(cat)
MakeNoise(dog)
}
// Sounder is the requirement for MakeNoise, so it lives with it.
// perhaps in a package together which knows nothing of cats and dogs.
type Sounder interface {
Sound() string
}
// MakeNoise prints the sound of the thing
// it only cares the thing makes a Sound
func MakeNoise(thing Sounder) {
println(thing.Sound())
}
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
}
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")
}