Kinda "method overloading" in Go? - go

Assuming I got a type named State:
type State struct {
// ... does not matter what is inside
}
along with a method defined on it:
func (s *State) prettyName() string {
return "I am a state!"
}
Currently there is no way I can alter prettyName()'s behavior. I known that Go intentionally escapes OOP-like inheritance and methods overloading and this would probably never change, but still: what if I need prettyName() to behave differently depending upon whatever factor? The only solution I see is:
type State struct {
_prettyName func() string
}
func (s *State) prettyName() string {
return s._prettyName()
}
Is there a better Go-style way to achieve the same goal?

An interface should work here.
creating an interface like
type Stateful interface {
State() string
}
and a base state type
type BaseState struct{
}
func (s BaseState) State() string{
return "Base state"
}
you can imbed the BaseState struct
type MyStruct struct{
BaseState
}
so that State Will return "Base state", but can also implement its own method.
func (s MyStruct) State() string{
return "New State"
}
and now State will return "New State"
https://play.golang.org/p/QOajW0O6gIz

Instead of having prettyName as method on the struct, you can also define a member value of function type.
type State struct {
prettyName func() string
}
Then you can set its value to any function at runtime
a := State{}
a.prettyName = func() string {
return "I am a state!"
}
fmt.Println(a.prettyName())
a.prettyName = func() string {
return "another state"
}
fmt.Println(a.prettyName())
This example is on playground
Now you can define an interface type with PrettyName API and further algorithms/business logic will call PrettyName.
type StateAPI interface {
PrettyName () string
}
To fit your State type into the StateAPI interface, you need to define a trivial PrettyName method around the private function member
func (s *State) PrettyName() string {
return s.prettyName()
}
This is basically your original idea and it is totally legitimate. There is an example in the go programming language book by Alan A. A. Donovan and Brian W. Kernighan with exactly this construct.
That example sorts music record by different fields, e.g., by year, by artist, etc. In order to use the sort.Sort API,
func Sort(data Interface)
The input data needs to have three methods
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less reports whether the element with
// index i should sort before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
One way to sort by different fields is to define one custom data type for each case, say ByYear, ByArtist, etc. And define all three API methods for each case. But Len and Swap methods are redundant for all cases. A better solution is to define only one custom data type with a function member,
//!+customcode
type customSort struct {
t []*Track
less func(x, y *Track) bool
}
func (x customSort) Less(i, j int) bool {
return x.less(x.t[i], x.t[j]) }
func (x customSort) Len() int {
return len(x.t) }
func (x customSort) Swap(i, j int) {
x.t[i], x.t[j] = x.t[j], x.t[i] }
Then you can programmically control what less means.
The source code is here

Related

Is it possible to properly infer type for interface embed in generic struct in GO? [duplicate]

In Go2 generics, as of current draft, I can specify a type constraint on a generic type using an interface.
import "fmt"
type Stringer interface {
String() string
}
func Print[T Stringer](value T) {
fmt.Println(value.String())
}
This way, I can specify, that the type must implement a method. However, I don't see any way to force the implementation of a method, with itself having an argument of the generic type.
type Lesser interface {
Less(rhs Lesser) bool
}
type Int int
func (lhs Int) Less(rhs Int) bool {
return lhs < rhs
}
func IsLess[T Lesser](lhs, rhs T) bool {
return lhs.Less(rhs)
}
func main() {
IsLess[Int](Int(10), Int(20))
}
Exits with
Int does not satisfy Lesser: wrong method signature
got func (Int).Less(rhs Int) bool
want func (Lesser).Less(rhs Lesser) bool
The original draft with contracts would make this possible, but not the new draft.
It can also be done with the following, but that would leave you with repeating the same constraint over and over again, braking DRY (and DRY code is the purpose of generics). It would also make the code much more unwieldy if the desired interfaces have multiple methods.
func IsLess[T interface { Less(T) bool }](lhs, rhs, T) bool {
return lhs.Less(rhs)
}
Is there any way to do this with a predefined interface in the new draft?
Define interface type Lesser and function Isless as follows:
type Lesser[T any] interface {
Less(T) bool
}
func IsLess[T Lesser[T]](x, y T) bool {
return x.Less(y)
}
Then, the following code compiles without mishap:
type Apple int
func (a Apple) Less(other Apple) bool {
return a < other
}
type Orange int
func (o Orange) Less(other Orange) bool {
return o < other
}
func main() {
fmt.Println(IsLess(Apple(10), Apple(20))) // true
fmt.Println(IsLess(Orange(30), Orange(15))) // false
// fmt.Println(IsLess(10, 30))
// compilation error: int does not implement Lesser[T] (missing method Less)
// fmt.Println(IsLess(Apple(20), Orange(30)))
// compilation error: type Orange of Orange(30) does not match inferred type Apple for T
}
(Playground)
The constraint T Lesser[T] may be read as
any type T that has a Less(T) bool method.
Both of my custom types,
Apple with its Less(Apple) bool method, and
Orange with its Less(Orange) bool method,
fulfil this requirement.
For information, Java generics allow a similar trick via what is known as a recursive type bound. For more on this topic, see item 30 (esp. p137-8) in Josh Bloch's Effective Java, 3rd edition.
Full disclosure: I was reminded of this unanswered question when I came across Vasko Zdravevski's solution to a similar problem on Gophers Slack.

How can I implement the same function for pointers to different structs?

Suppose I have a lot of different structs, but they all share a common field, such as "name". For example:
type foo struct {
name string
someOtherString string
// Other fields
}
type bar struct {
name string
someNumber int
// Other fields
}
Further on in the program, I repeatedly encounter the situation where I get pointers to these structs (so *foo, *bar, etc.) and need to perform operations depending on whether the pointer is nil or not, basically like so:
func workOnName(f *foo) interface{} {
if (f == nil) {
// Do lots of stuff
} else {
// Do lots of other stuff
}
// Do even more stuff
return something
}
This function, which only uses name, is the same across all structs. If these were not pointers, I know I could write a common interface for each struct that returns the name and use that as the type. But with pointers, none of this has worked. Go either complains while compiling, or the nil check doesn't work and Go panics. I haven't found anything smarter than to copy/paste the exact same code for every struct that I have, so basically to implement all the functions:
func (f *foo) workOnName() interface{}
func (b *bar) workOnName() interface{}
func (h *ham) workOnName() interface{}
// And so on...
Is there a way to do this better, i.e. to only implement a simple function (or even better, no function at all) for all my structs and simply write the complicated stuff once, for all the structs?
Edit: Thank you to the answers so far, but simply using an interface of the type:
func (f foo) Name() string {
return f.name
}
for some interface that provides Name() does not work, because the pointer is not recognized as nil. See this playground: https://play.golang.org/p/_d1qiZwnMe_f
You can declare an interface which declares a function returning a name:
type WithName interface {
Name() string
}
In order to implement that interface, you types (foo, bar, etc) need to have that method - not just the field, the method.
func (f foo) Name() string {
return f.name
}
Then, workOnName needs to receive a reference of that interface:
func workOnName(n WithName) interface{} {
if (n == nil || reflect.ValueOf(n).isNil()) {
// Do lots of stuff
} else {
// Do lots of other stuff
}
// Do even more stuff
return something
}
Keep in mind that the parameter n WithName is always treated as a pointer, not an object value.
I think that's the case for reflect.
Something like:
package main
import (
"fmt"
"reflect"
)
func SetFieldX(obj, value interface{}) {
v := reflect.ValueOf(obj).Elem()
if !v.IsValid() {
fmt.Println("obj is nil")
return
}
f := v.FieldByName("X")
if f.IsValid() && f.CanSet() {
f.Set(reflect.ValueOf(value))
}
}
func main() {
st1 := &struct{ X int }{10}
var stNil *struct{}
SetFieldX(st1, 555)
SetFieldX(stNil, "SSS")
fmt.Printf("%v\n%v\n", st1, stNil)
}
https://play.golang.org/p/OddSWT4JkSG
Note that IsValid checks more than just obj==nil but if you really want to distinguish cases of nil pointers and non-struct objects - you are free to implement it.

type INode* is pointer to interface, not interface

So trying out go for the first time today and keep running into an error to do with interfaces, I guess I don't understand them correctly. Ive tried looking around for an answer but the terminology that I'm used to is a little different from other languages so I can't piece it together. As practice I decided to implement a very simple linked list but the error I recieve is:
type INode* is pointer to interface, not interface when calling .setNext(node *Inode)
What is the reason behind this? what piece of information am I missing with interfaces?
Heres the incomplete implementation:
package main
type object interface{}
type INode interface {
GetData() object
GetNext() *INode
setNext(node *INode)
}
type ILinkedList interface {
Link(node *INode)
Unlink(node *INode)
CurrentLength() int
RemoveAt(idx int)
}
type Node struct {
data object
next *INode
}
func (n *Node) GetData() object {
return n.data
}
func (n *Node) GetNext() *INode {
return n.next
}
func (n *Node) setNext(node *INode) {
n.next = node
}
type LinkedList struct {
cur *INode
last *INode
length int
}
func (l *LinkedList) Link(node *INode) {
if l == nil {
return
}
if l.cur == nil {
l.cur = node
l.last = node
} else {
l.last.setNext(node)
l.last = node
}
l.length = l.length + 1
}
This is because in Go, an interface is just a specification of behavior. This behavior can be implemented with either a pointer receiver or a value receiver. The interface doesn't care which one is ultimately used, just as long as it fulfills the interface contract.
See this example:
https://play.golang.org/p/0AaBhB1MHBc
type I interface {
M()
}
type T struct {
S string
}
func (t T) M(){
fmt.Println("T.M fired");
}
type S struct {
S string
}
func (s *S) M(){
fmt.Println("*S.M fired");
}
func RunM(i I){
i.M()
}
func main() {
test1 := T{}
test2 := &S{}
RunM(test1)
RunM(test2)
fmt.Println("Hello, playground")
}
Both pointers to the S type and T types implement the interface I, and can be passed in to any func requiring an I. The interface doesn't care if it's a pointer or not.
You can read up about pointer receivers here: https://tour.golang.org/methods/4
I thought I would post a reference for those visiting in the future that have the same issue regarding pointers to interfaces:
When should I use a pointer to an interface?
Almost never. Pointers to interface values arise only in rare, tricky
situations involving disguising an interface value's type for delayed
evaluation.
It is however a common mistake to pass a pointer to an interface value
to a function expecting an interface. The compiler will complain about
this error but the situation can still be confusing, because sometimes
a pointer is necessary to satisfy an interface. The insight is that
although a pointer to a concrete type can satisfy an interface, with
one exception a pointer to an interface can never satisfy an
interface.
Consider the variable declaration,
var w io.Writer The printing function fmt.Fprintf takes as its first
argument a value that satisfies io.Writer—something that implements
the canonical Write method. Thus we can write
fmt.Fprintf(w, "hello, world\n") If however we pass the address of w,
the program will not compile.
fmt.Fprintf(&w, "hello, world\n") // Compile-time error. The one
exception is that any value, even a pointer to an interface, can be
assigned to a variable of empty interface type (interface{}). Even so,
it's almost certainly a mistake if the value is a pointer to an
interface; the result can be confusing.

Wrapping multiple implementations in Go

I have an application that has multiple concurrent implementations of the same API (e.g. one backed by a SQL database and another by a dataset stored in an XML file). What I'd really like to do is to define a parent type for each type of thing in the API that
holds the member variables that are common to all of the implementations and
defines the methods that all implementations must have.
So, in (invalid) Go, I want to do something like:
type Person interface {
Name string
Title string
Position string
Boss() *Person
}
type Person_XML struct {
Person
}
func (p *Person_XML) Boss() (*Person, error) {
// Poke around an XML document and answer the question
return boss, nil
}
type Person_SQL {
Person
}
func (p *Person_SQL) Boss() (*Person, error) {
// Do a DB query and construct the record for the boss
return boss, nil
}
But, of course, that's not legal since only structs have member variables and only interfaces have member functions. I could do this with just interfaces like this:
type Person interface {
Name() string
Title() string
Position() string
Boss() Person
}
type Person_XML struct {
NameValue string
TitleValue string
PositionValue string
Person
}
func (p *Person_XML) Name() string {
return p.NameValue
}
func (p *Person_XML) Title() string {
return p.TitleValue
}
func (p *Person_XML) Position() string {
return p.PositionValue
}
func (p *Person_XML) Boss() (Person, error) {
// Poke around an XML document and answer the question
return boss, nil
}
and similarly for other implementations. Is there an alternative that doesn't force me to turn member variables into member functions? What's best practice for such a use case?
Best practice would be to provide an interface:
type Person interface {
PersonName() string
PersonTitle() string
PersonPosition() string
Boss() (Person, error)
}
And also provide a struct which contains the common fields and the methods to get them:
type BasePerson struct {
Name string
Title string
Position string
}
func (p *BasePerson) PersonName() string { return p.Name }
func (p *BasePerson) PersonTitle() string { return p.Title }
func (p *BasePerson) PersonPosition() string { return p.Position }
(Note: *BasePerson itself does not implement Person as it doesn't have a Boss() method.)
Any type that embeds *BasePerson will automatically have its methods promoted, and so to implement Person, only the Boss() method will need to be added.
For example:
type PersonXML struct {
*BasePerson
}
func (p *PersonXML) Boss() (Person, error) {
// Poke around an XML document and answer the question
var boss *PersonXML
return boss, nil
}
*PersonXML does implement Person.
Example using it:
var p Person
p = &PersonXML{
BasePerson: &BasePerson{
Name: "Bob",
Title: "sysadmin",
Position: "leader",
},
}
fmt.Println(p.PersonName())
Output (try it on the Go Playground):
Bob
To create the PersonSQL type, you again only have to add the Boss() method if you embed *BasePerson:
type PersonSQL struct {
*BasePerson
}
func (p *PersonSQL) Boss() (Person, error) {
// Do a DB query and construct the record for the boss
var boss *PersonSQL
return boss, nil
}
*PersonSQL again does implement Person.
We can apply first approach since struct can embed interface along with fields. If you look at package sort It uses same approach in which it embeds an interface inside an struct.
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less reports whether the element with
// index i should sort before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
type reverse struct {
// This embedded Interface permits Reverse to use the methods of
// another Interface implementation.
Interface
}
So doing your approach is absolutely valid. And you can implement interface easily using struct receiver.
// Less returns the opposite of the embedded implementation's Less method.
func (r reverse) Less(i, j int) bool {
return r.Interface.Less(j, i)
}

How to make possible to return structs of different types from one function with Golang?

I have a function which queries database, then, depending on result form it, can create a struct OrderWithoutDetails or OrderWithDetails depending on the presence of details about the order.
How do I make the function to be able to return result of both types?
You can use interface{}
func queryDb() interface{}{
}
But the better will be if your 2 type of struct can have a common function, that can satisfy a common interface, it will be cleaner.
Example :
type s1 struct{
id int
name string
}
type s2 struct{
id int
age int
}
type reDB interface {
my_print()
}
func (r *s1) my_print(){
fmt.Print(s1.id)
}
func (r *s2) my_print(){
fmt.Print(s1.id)
}
func queryDb() reDB{
...
}

Resources