Adding a method for existing type in Golang: how to rewrite return value's type - go

I want to extend existing goquery.Selection type with my own method and be able to use it from package's selectors. I know that I cannot "patch" existing method -- I need to create a new one. But how do I can force the existing package functions to use my new type? Something I'm missing in general or there's no "nice" way to do it and it's better to use a function?
package main
import (
"fmt"
"github.com/PuerkitoBio/goquery"
)
type customSelection goquery.Selection
func (s *customSelection) CustomMethod() int {
return 1
}
doc.Find("*").Each(func(i int, s *goquery.Selection) {
fmt.Println(s.CustomMethod()) // does not works since its still "goquery.Selection"
// how do I can get a result with customSelection type here?
})

Since inheritance is not supported, the best practice is to embed the non-local type into your own local type, and extend it.
In the Design Patterns lingo its better known as composition:
https://en.wikipedia.org/wiki/Composition_over_inheritance

You can use function instead of method:
func customFunc(s *goquery.Selection) int {
return 1
}
...
fmt.Println(customFunc(s))

Related

In GoLang, how do you isolate packages that return more than a primitive value?

If I have a requests package that defines an interface TextExtractor with a GetText method that returns a Text type, the implementations must fulfill the TextExtractor contract exactly, and they are forced to import the Text type.
I have two possible implementations of TextExtractor - one that uses AWS Comprehend and one that uses AWS Textract.
aws_comprehend.go
package aws_comprehend
type AwsComprehend struct{}
func (a *AwsComprehend) GetText() *Text {
// do some stuff with aws comprehend...
return &Text{
Text: "text",
Language: "language",
}
}
type Text struct {
Text string
Language string
}
request.go
package requests
import "fmt"
type TextExtractor interface {
GetText() *Text
}
type Text struct {
Text string
Language string
}
func HandleRequest(textExtractor TextExtractor) {
text := textExtractor.GetText()
fmt.Println(text)
}
main.go
package main
import (
"aws_comprehend"
"requests"
)
func main() {
textExtractor := new(aws_comprehend.AwsComprehend)
requests.HandleRequest(textExtractor)
// this does not work:
// cannot use textExtractor (variable of type *aws_comprehend.AwsComprehend) as
// requests.TextExtractor value in argument to requests.HandleRequest:
// *aws_comprehend.AwsComprehend does not implement requests.TextExtractor
// (wrong type for method GetText)
// have GetText() *aws_comprehend.Text
// want GetText() *requests.Text
}
I understand why this doesn't work. It's because GoLang doesn't support Covariant Result Types. But my question is, what is the standard way to code this situation? The fact that GoLang provides implicit interfaces means that isolating packages is very easy: the calling package defines the interfaces that it uses, and it is passed implementations that fulfill those interfaces. This means that packages don't have to reference each other at all. But if a package defines an interface that returns anything more than a primitive value, then you have to deliberately share those value types. The code above would be fine if GetText returned a string. But the fact that it returns a struct or another interface, means the code can't be written this way.
I want the requests package not to know anything about the aws_comprehend package. This is because I have two implementations of the TextExtractor interface: One that uses AWS Comprehend, and one that uses AWS Textract. I also would prefer not to include a "intermediate" package that has interfaces that both the requests package and the aws_comprehend package inherit from. If both packages have to inherit the same interface, then it seems like it's just indirect coupling to me and it ruins the idea of a implicit interfaces.
I understand that GoLang is very opinionated - So what is the standard way to solve this problem?
first, your file layout is not valid. you cant have two files in the same
folder, with different packages. so below is a corrected layout. also I removed
all pointers, because they aren't needed for this example and are just distracting.
Finally, I updated the method to return the correct type, so that the code
actually compiles:
aws_comprehend/aws_comprehend.go:
package aws_comprehend
import "hello/requests"
type AwsComprehend struct{}
func (AwsComprehend) GetText() requests.Text {
return requests.Text{}
}
requests/request.go:
package requests
import "fmt"
type TextExtractor interface {
GetText() Text
}
type Text struct {
Language string
Text string
}
func HandleRequest(textExtractor TextExtractor) {
text := textExtractor.GetText()
fmt.Println(text)
}
main.go:
package main
import (
"hello/aws_comprehend"
"hello/requests"
)
func main() {
var textExtractor aws_comprehend.AwsComprehend
requests.HandleRequest(textExtractor)
}

How can an external package implement an interface implicitly?

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.

Idiomatic way to have a copy method in an interface

What is the idiomatic way to have a Copy() method in an interface in Go?
I have a struct S that can return a copy of itself.
I also want an interface that can be implemented by anything that can return a copy of itself.
The code below won't compile because you cannot use S literal (type S) as type I in assignment, but this is basically what I'm trying to do.
I also don't want to change (S) Copy() S to (S) Copy() I because: "The implementing package should return concrete types"
https://github.com/golang/go/wiki/CodeReviewComments#interfaces
I understand I probably need generics or something, but short of that, how are we supposed to handle this kind of situation?
package main
type S struct {
}
func (S) Copy() S {
return S{}
}
//====== another package ======
type I interface {
Copy() I
}
func main() {
var i I = S{}
i.Copy()
}
The only way to do this without generics is to define the Copy method to return the interface:
func (S) Copy() I {...}
You have to return interfaces when you need to.

Doesn't see public functions of a struct Golang

I don't see the public method of the struct that I defined.
Can someone please let me understand why?
Here is the code:
// DataSaver.go:
package DataStorage
import (
"fmt"
"os"
)
type DataSaver struct {
// doesn't relevant to my question
fileName string
file *os.File
}
func PrintStr() {
fmt.Println("hello")
}
Then, I have a main method in other class. I initialized the struct and I wanted to call to PrintStr() function. However, I can't call to this method. Why?
Thank you!
That is not a method, it is just a function.
Import DataStorage (you should make it lower case) then you can call DataStorage.PrintStr()
I had a play around myself with this, and there are a few things to be careful of:
Make sure you import the package properly with respect to your GOPATH, e.g.
import "github.com/some-repo/datastorage"
And ensure that your packages/repos are in your GOPATH and in the correct directories (go is very fussy about how you do this)
Refer to your function using the package name like so:
func main(){
DataStorage.PrintStr()
}
The other poster is correct in that go conventions are to keep package names in lowercase.
Seems you dont have the concept of method receiver yet. Your method for the struct should be defined as below :
func (this DataSaver)PrintStr() {
fmt.Println("hello")
}
or
func (this *DataSaver)PrintStr() {
fmt.Println("hello")
}
which one you choose depends on you want to call the method on a pointer or not;

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
}

Resources