Polymorphism in Go - does it exist? - go

I am trying to make something real simple on Go: to have an interface with getter and setter methods. And it seems setter methods are not allowed.
Given this code:
package main
import "fmt"
type MyInterfacer interface {
Get() int
Set(i int)
}
type MyStruct struct {
data int
}
func (this MyStruct) Get() int {
return this.data
}
func (this MyStruct) Set(i int) {
this.data = i
}
func main() {
s := MyStruct{123}
fmt.Println(s.Get())
s.Set(456)
fmt.Println(s.Get())
var mi MyInterfacer = s
mi.Set(789)
fmt.Println(mi.Get())
}
Set method does not work, because in func (this MyStruct) Set(i int), this MyStruct is not a pointer, and the changes are lost as soon at the function exits. But making it this *MyStruct would not compile. Is there any workaround?

Here is a corrected version of your code (playground). This isn't exactly Polymorphism, but the use of an interface is good Go style.
package main
import "fmt"
type MyInterfacer interface {
Get() int
Set(i int)
}
type MyStruct struct {
data int
}
func (this *MyStruct) Get() int {
return this.data
}
func (this *MyStruct) Set(i int) {
this.data = i
}
func main() {
s := &MyStruct{123}
fmt.Println(s.Get())
s.Set(456)
fmt.Println(s.Get())
var mi MyInterfacer = s
mi.Set(789)
fmt.Println(mi.Get())
}

I once found this example of how to do polymorphism in Go:
http://play.golang.org/p/6Ip9scm4c3
package main
import "fmt"
type Talker interface {
Talk(words string)
}
type Cat struct {
name string
}
type Dog struct {
name string
}
func (c *Cat) Talk(words string) {
fmt.Printf("Cat " + c.name + " here: " + words + "\n")
}
func (d *Dog) Talk(words string) {
fmt.Printf("Dog " + d.name + " here: " + words + "\n")
}
func main() {
var t1, t2 Talker
t1 = &Cat{"Kit"}
t2 = &Dog{"Doug"}
t1.Talk("meow")
t2.Talk("woof")
}

To answer the question the in the title to post:
Go does not use classes, but provides many of the same features:
* message passing with methods
* automatic message delegation via embedding
* polymorphism via interfaces
* namespacing via exports
From: http://nathany.com/good/
Solving the code you supplied, I will leave to some more learned Gopher

###AD HOC polymophism
Ad hoc polymorphism is a general way of polymorphism implementation for statically typed languages. Polymorphism in Go is ad hoc polymorphism which is very close to Bjarne's Stroustrup definition:
Polymorphism – providing a single interface to entities of different types.
Interfaces
Go interface is really powerful tool designed specially for polymorphism implementation. Interface is a type abstraction (sets of methods) which provides a way to specify the behavior of an object: if something can do this, then it can be used here. Back to Straustrup's polymorphism definition: it is possible to use objects of different types as a type of a common interface if they implement the interface.
Playground with an example.
Parametric polymorphism
Wiki:
A function or a data type can be written generically so that it can handle values identically without depending on their type.
This kind of polymorphism is more regular for dynamically typed languages like Python or Ruby but Go implements it too! Go uses type empty interface interface{} for this purpose.
Type interface{}
From Tour Of Go:
The interface type that specifies zero methods is known as the empty interface:
interface{}
An empty interface may hold values of any type. Every type implements at least zero methods.
Empty interfaces are used by code that handles values of unknown type. For example, fmt.Print takes any number of arguments of type interface{}.
And it is possible to get particular type of an object with type assertion.
And again Tour Of Go:
A type assertion provides access to an interface value's underlying concrete value.
t := i.(T)
This statement asserts that the interface value i holds the concrete type T and assigns the underlying T value to the variable t.
There we have parametric polymorphism with static duck typing.

Related

golang generics with constraints on pointer reciever [duplicate]

Probably a golang beginner's question :)
I'm facing following compiler error when trying to compile the code below.
I want to implement an object store for different types (here A and B) sharing a common ID field. Following the DRY idea, I want to implement the store using generics.
When adding an object, I want to set its ID field using the GS interface (the actual code is a bit more complex of course), but the compiler does not want me to do that.
./prog.go:29:7: item.SetId undefined (type *T is pointer to type parameter, not type parameter)
./prog.go:34:24: A does not implement GS (SetId method has pointer receiver)
Is there a recommended way to solve this? Thanks in advance!!
package main
import "fmt"
type A struct {
ID string
AMember string
}
type B struct {
ID string
BMember string
}
type GS interface {
Id() string
SetId(string)
}
func (s A) Id() string { return s.ID }
func (s *A) SetId(i string) { s.ID = i }
func (s B) Id() string { return s.ID }
func (s *B) SetId(i string) { s.ID = i }
type MyStore[T GS] struct {
values map[string]*T
}
func (s *MyStore[T]) add(item *T) {
item.SetId("aa")
s.values["aa"] = item
}
func main() {
var storeA = &MyStore[A]{}
storeA.values = make(map[string]*A)
a := &A{}
storeA.add(a)
fmt.Println(a.Id())
}
About using *T
In short, a type parameter is not its constraint. The constraint only determines what operations are available on T, it doesn't imply anything about *T, which is now just an unnamed pointer type. This is the meaning of:
type *T is pointer to type parameter, not type parameter
As a consequence, as in your case, the method set of *T does not automatically include pointer receiver methods declared on the T's concrete type A, and it does not implement interfaces that would be implemented by *A.
You'd have to make that explicit to the compiler by setting additional constraints. In a simplified form it would be something like:
func Foo[T any, PT interface { SetId(string); *T}](v T) {}
You can find more extensive examples and variations on this use case here:
Go 1.18 Generics how to define a new-able type parameter with interface
How can I instantiate a new pointer of type argument with generic Go?
What is the generic type for a pointer that implements an interface?
About implementing constraints
The reason this instantiation &MyStore[A]{} fails is clearly reported by the error message:
A does not implement GS (SetId method has pointer receiver)
In other words SetId() is declared on *A, and not A. Therefore you should instantiate MyStore with *A:
var storeA = &MyStore[*A]{}
Then change the occurrences of *T in the struct/method definition to T:
type MyStore[T GS] struct {
values map[string]T // just T instead of *T
}
func (s *MyStore[T]) add(item T) {
}
Upon instantiation with *A the type of the field would become equivalent to map[string]*A thus making the assignment storeA.values = make(map[string]*A) valid, and the method signature to add(item *A) thus allowing storeA.add(&A{}).
Fixed playground: https://gotipplay.golang.org/p/dcUVJ5YQK_b

Go with Generics: type *T is pointer to type parameter, not type parameter

Probably a golang beginner's question :)
I'm facing following compiler error when trying to compile the code below.
I want to implement an object store for different types (here A and B) sharing a common ID field. Following the DRY idea, I want to implement the store using generics.
When adding an object, I want to set its ID field using the GS interface (the actual code is a bit more complex of course), but the compiler does not want me to do that.
./prog.go:29:7: item.SetId undefined (type *T is pointer to type parameter, not type parameter)
./prog.go:34:24: A does not implement GS (SetId method has pointer receiver)
Is there a recommended way to solve this? Thanks in advance!!
package main
import "fmt"
type A struct {
ID string
AMember string
}
type B struct {
ID string
BMember string
}
type GS interface {
Id() string
SetId(string)
}
func (s A) Id() string { return s.ID }
func (s *A) SetId(i string) { s.ID = i }
func (s B) Id() string { return s.ID }
func (s *B) SetId(i string) { s.ID = i }
type MyStore[T GS] struct {
values map[string]*T
}
func (s *MyStore[T]) add(item *T) {
item.SetId("aa")
s.values["aa"] = item
}
func main() {
var storeA = &MyStore[A]{}
storeA.values = make(map[string]*A)
a := &A{}
storeA.add(a)
fmt.Println(a.Id())
}
About using *T
In short, a type parameter is not its constraint. The constraint only determines what operations are available on T, it doesn't imply anything about *T, which is now just an unnamed pointer type. This is the meaning of:
type *T is pointer to type parameter, not type parameter
As a consequence, as in your case, the method set of *T does not automatically include pointer receiver methods declared on the T's concrete type A, and it does not implement interfaces that would be implemented by *A.
You'd have to make that explicit to the compiler by setting additional constraints. In a simplified form it would be something like:
func Foo[T any, PT interface { SetId(string); *T}](v T) {}
You can find more extensive examples and variations on this use case here:
Go 1.18 Generics how to define a new-able type parameter with interface
How can I instantiate a new pointer of type argument with generic Go?
What is the generic type for a pointer that implements an interface?
About implementing constraints
The reason this instantiation &MyStore[A]{} fails is clearly reported by the error message:
A does not implement GS (SetId method has pointer receiver)
In other words SetId() is declared on *A, and not A. Therefore you should instantiate MyStore with *A:
var storeA = &MyStore[*A]{}
Then change the occurrences of *T in the struct/method definition to T:
type MyStore[T GS] struct {
values map[string]T // just T instead of *T
}
func (s *MyStore[T]) add(item T) {
}
Upon instantiation with *A the type of the field would become equivalent to map[string]*A thus making the assignment storeA.values = make(map[string]*A) valid, and the method signature to add(item *A) thus allowing storeA.add(&A{}).
Fixed playground: https://gotipplay.golang.org/p/dcUVJ5YQK_b

Assign struct pointer to interface pointer

I'm trying to refactor some golang source code, and I would like to use interfaces but I find huge difficulties (bear with me, I'm a hard-core C/C++ orphan)
I extracted a small sample exhibiting the error I get
package main
import "fmt"
type LogProcessor interface {
Init() int
}
type MyProcessor struct {
a int
}
func (m MyProcessor) Init() int {
return m.a
}
func main() {
t := &(MyProcessor{2})
var p *LogProcessor = &(MyProcessor{4}) //!!!fails!!!
fmt.Println((*t).Init(), (*p).Init())
}
Why is the second assignment failing?
Adding the code modified to demonstrate what I was trying to do. I thought interfaces where more similar to C++ classes. My fault. Still learning
package main
import "fmt"
type LogProcessor interface {
Init() int
}
type MyProcessor struct {
a int
}
func (m *MyProcessor) Init() int {
m.a++
return m.a
}
func main() {
t := &(MyProcessor{2})
m := MyProcessor{4}
var p LogProcessor = &m
fmt.Println(t.Init(), p.Init())
fmt.Println(t.a, m.a)
}
The expression MyProcessor{2} is a composite literal. It is valid to take the address of a composite literal, and it will be of type *MyProcessor.
So here:
t := &(MyProcessor{2})
Type of t will be *MyProcessor.
Your failing line:
var p *LogProcessor = &(MyProcessor{4}) //!!!fails!!!
The type of the expression on the right hand side is again *MyProcessor. It's a pointer to a concrete type. The type of p is *LogProcessor, it's a pointer to another type. Assignability rules don't apply here, so the value is simply not assignable to the variable p.
Note that there is an assignability rule:
A value x is assignable to a variable of type T ("x is assignable to T") if one of the following conditions applies:
...
T is an interface type and x implements T.
In your example p's type is not an interface type, but a pointer to interface. You rarely (if ever) need this in go.
Instead if you use "just" the interface type:
var p LogProcessor = &(MyProcessor{4}) // This works!
This works because the concrete type *MyProcessor implements the interface type LogProcessor. You also don't need the parenthesis, you may simply use &MyProcessor{4}.
Then of course you can't dereference p (as it's not a pointer), so you have to use p.Init().
it is failing because you are using a pointer to an interface, if you remove the pointer to LogProcessor for var p it works
package main
import "fmt"
type LogProcessor interface {
Init() int
}
type MyProcessor struct {
a int
}
func (m MyProcessor) Init() int {
return 2
}
func main() {
t := &(MyProcessor{2})
var p LogProcessor = MyProcessor{4} // works without a pointer to the interface type
fmt.Println((*t).Init(), (p).Init())
}

Forcing Go types to implement an interface

In Go, you don’t state that you need to implement an interface, you just do it (it’s called ‘structural typing’ similar to ‘duck typing’ in dynamic languages).
What if you want to force a type to implement an interface (like when you ‘inherit’ an interface in C# or Java for instance)? In other words, what if forgetting to implement an interface (or getting the signature wrong) is a mistake and you want to catch that mistake early. What is the best way to do it?
Best thing you may do is try to assign an instance of the type to a interface variable
For example you want to make sure type A implements Stringer interface.
You may do like this
var _ Stringer = new(A) //or
var _ Stringer = A{}
Here is the sample program, In the example A implements the interface and B does not
package main
import (
"fmt"
)
type Stringer interface {
String() string
}
type A struct {
}
func (a A) String() string {
return "A"
}
type B struct {}
var _ Stringer = new(A)
var _ Stringer = new(B)
func main() {
fmt.Println("Hello, playground")
}
Play link here : play.golang
To complete what #Sarathsp said:
Basically, by declaring a dummy variable (underscore means that it is not used) of the interface type while assigning an instance of your type to it, you get very explicit compile-time errors:
type MyType struct {
}
func (*MyType) Read() {
}
var _ io.Reader = &MyType{}
cannot use MyType literal (type *MyType) as type io.Reader in assignment:
*MyType does not implement io.Reader (missing Read method)
Or
cannot use MyType literal (type *MyType) as type io.Reader in assignment:
*MyType does not implement io.Reader (wrong type for Read method)
have Read()
want Read([]byte) (int, error)

Meaning of a struct with embedded anonymous interface?

sort package:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
...
type reverse struct {
Interface
}
What is the meaning of anonymous interface Interface in struct reverse?
In this way reverse implements the sort.Interface and we can override a specific method
without having to define all the others
type reverse struct {
// This embedded Interface permits Reverse to use the methods of
// another Interface implementation.
Interface
}
Notice how here it swaps (j,i) instead of (i,j) and also this is the only method declared for the struct reverse even if reverse implement sort.Interface
// 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)
}
Whatever struct is passed inside this method we convert it to a new reverse struct.
// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
return &reverse{data}
}
The real value comes if you think what would you have to do if this approach was not possible.
Add another Reverse method to the sort.Interface ?
Create another ReverseInterface ?
... ?
Any of this change would require many many more lines of code across thousands of packages that want to use the standard reverse functionality.
Ok, the accepted answer helped me understand, but I decided to post an explanation which I think suits better my way of thinking.
The "Effective Go" has example of interfaces having embedded other interfaces:
// ReadWriter is the interface that combines the Reader and Writer interfaces.
type ReadWriter interface {
Reader
Writer
}
and a struct having embedded other structs:
// ReadWriter stores pointers to a Reader and a Writer.
// It implements io.ReadWriter.
type ReadWriter struct {
*Reader // *bufio.Reader
*Writer // *bufio.Writer
}
But there is no mention of a struct having embedded an interface. I was confused seeing this in sort package:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
...
type reverse struct {
Interface
}
But the idea is simple. It's almost the same as:
type reverse struct {
IntSlice // IntSlice struct attaches the methods of Interface to []int, sorting in increasing order
}
methods of IntSlice being promoted to reverse.
And this:
type reverse struct {
Interface
}
means that sort.reverse can embed any struct that implements interface sort.Interface and whatever methods that interface has, they will be promoted to reverse.
sort.Interface has method Less(i, j int) bool which now can be overridden:
// 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)
}
My confusion in understanding
type reverse struct {
Interface
}
was that I thought that a struct always has fixed structure, i.e. fixed number of fields of fixed types.
But the following proves me wrong:
package main
import "fmt"
// some interface
type Stringer interface {
String() string
}
// a struct that implements Stringer interface
type Struct1 struct {
field1 string
}
func (s Struct1) String() string {
return s.field1
}
// another struct that implements Stringer interface, but has a different set of fields
type Struct2 struct {
field1 []string
dummy bool
}
func (s Struct2) String() string {
return fmt.Sprintf("%v, %v", s.field1, s.dummy)
}
// container that can embedd any struct which implements Stringer interface
type StringerContainer struct {
Stringer
}
func main() {
// the following prints: This is Struct1
fmt.Println(StringerContainer{Struct1{"This is Struct1"}})
// the following prints: [This is Struct1], true
fmt.Println(StringerContainer{Struct2{[]string{"This", "is", "Struct1"}, true}})
// the following does not compile:
// cannot use "This is a type that does not implement Stringer" (type string)
// as type Stringer in field value:
// string does not implement Stringer (missing String method)
fmt.Println(StringerContainer{"This is a type that does not implement Stringer"})
}
The statement
type reverse struct {
Interface
}
enables you to initialize reverse with everything that implements the interface Interface. Example:
&reverse{sort.Intslice([]int{1,2,3})}
This way, all methods implemented by the embedded Interface value get populated to the outside while you are still able to override some of them in reverse, for example Less to reverse the sorting.
This is what actually happens when you use sort.Reverse. You can read about embedding in the struct section of the spec.
I will give my explanation too. The sort package defines an unexported type reverse, which is a struct, that embeds Interface.
type reverse struct {
// This embedded Interface permits Reverse to use the methods of
// another Interface implementation.
Interface
}
This permits Reverse to use the methods of another Interface implementation. This is the so called composition, which is a powerful feature of Go.
The Less method for reverse calls the Less method of the embedded Interface value, but with the indices flipped, reversing the order of the sort results.
// 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)
}
Len and Swap the other two methods of reverse, are implicitly provided by the original Interface value because it is an embedded field. The exported Reverse function returns an instance of the reverse type that contains the original Interface value.
// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
return &reverse{data}
}
I find this feature very helpful when writing mocks in tests.
Here is such an example:
package main_test
import (
"fmt"
"testing"
)
// Item represents the entity retrieved from the store
// It's not relevant in this example
type Item struct {
First, Last string
}
// Store abstracts the DB store
type Store interface {
Create(string, string) (*Item, error)
GetByID(string) (*Item, error)
Update(*Item) error
HealthCheck() error
Close() error
}
// this is a mock implementing Store interface
type storeMock struct {
Store
// healthy is false by default
healthy bool
}
// HealthCheck is mocked function
func (s *storeMock) HealthCheck() error {
if !s.healthy {
return fmt.Errorf("mock error")
}
return nil
}
// IsHealthy is the tested function
func IsHealthy(s Store) bool {
return s.HealthCheck() == nil
}
func TestIsHealthy(t *testing.T) {
mock := &storeMock{}
if IsHealthy(mock) {
t.Errorf("IsHealthy should return false")
}
mock = &storeMock{healthy: true}
if !IsHealthy(mock) {
t.Errorf("IsHealthy should return true")
}
}
By using:
type storeMock struct {
Store
...
}
One doesn't need to mock all Store methods. Only HealthCheck can be mocked, since only this method is used in the TestIsHealthy test.
Below the result of the test command:
$ go test -run '^TestIsHealthy$' ./main_test.go
ok command-line-arguments 0.003s
A real world example of this use case one can find when testing the AWS SDK.
To make it even more obvious, here is the ugly alternative - the minimum one needs to implement to satisfy the Store interface:
type storeMock struct {
healthy bool
}
func (s *storeMock) Create(a, b string) (i *Item, err error) {
return
}
func (s *storeMock) GetByID(a string) (i *Item, err error) {
return
}
func (s *storeMock) Update(i *Item) (err error) {
return
}
// HealthCheck is mocked function
func (s *storeMock) HealthCheck() error {
if !s.healthy {
return fmt.Errorf("mock error")
}
return nil
}
func (s *storeMock) Close() (err error) {
return
}
Embedding interfaces in a struct allows for partially "overriding" methods from the embedded interfaces. This, in turn, allows for delegation from the embedding struct to the embedded interface implementation.
The following example is taken from this blog post.
Suppose we want to have a socket connection with some additional functionality, like counting the total number of bytes read from it. We can define the following struct:
type StatsConn struct {
net.Conn
BytesRead uint64
}
StatsConn now implements the net.Conn interface and can be used anywhere a net.Conn is expected. When a StatsConn is initialized with a proper value implementing net.Conn for the embedded field, it "inherits" all the methods of that value; the key insight is, though, that we can intercept any method we wish, leaving all the others intact. For our purpose in this example, we'd like to intercept the Read method and record the number of bytes read:
func (sc *StatsConn) Read(p []byte) (int, error) {
n, err := sc.Conn.Read(p)
sc.BytesRead += uint64(n)
return n, err
}
To users of StatsConn, this change is transparent; we can still call Read on it and it will do what we expect (due to delegating to sc.Conn.Read), but it will also do additional bookkeeping.
It's critical to initialize a StatsConn properly, otherwise the field retains its default value nil causing a runtime error: invalid memory address or nil pointer dereference; for example:
conn, err := net.Dial("tcp", u.Host+":80")
if err != nil {
log.Fatal(err)
}
sconn := &StatsConn{conn, 0}
Here net.Dial returns a value that implements net.Conn, so we can use that to initialize the embedded field of StatsConn.
We can now pass our sconn to any function that expects a net.Conn argument, e.g:
resp, err := ioutil.ReadAll(sconn)
if err != nil {
log.Fatal(err)
And later we can access its BytesRead field to get the total.
This is an example of wrapping an interface. We created a new type that implements an existing interface, but reused an embedded value to implement most of the functionality. We could implement this without embedding by having an explicit conn field like this:
type StatsConn struct {
conn net.Conn
BytesRead uint64
}
And then writing forwarding methods for each method in the net.Conn interface, e.g.:
func (sc *StatsConn) Close() error {
return sc.conn.Close()
}
However, the net.Conn interface has many methods. Writing forwarding methods for all of them is tedious and unnecessary. Embedding the interface gives us all these forwarding methods for free, and we can override just the ones we need.
I will try another, low level approach to this.
Given the reverse struct:
type reverse struct {
Interface
}
This beside others means, that reverse struct has a field reverse.Interface, and as a struct fields, it can be nil or have value of type Interface.
If it is not nil, then the fields from the Interface are promoted to the "root" = reverse struct. It might be eclipsed by fields defined directly on the reverse struct, but that is not our case.
When You do something like:
foo := reverse{}, you can println it via fmt.Printf("%+v", foo) and got
{Interface:<nil>}
When you do the
foo := reverse{someInterfaceInstance}
It is equivalent of:
foo := reverse{Interface: someInterfaceInstance}
It feels to me like You declare expectation, that implementation of Interface API should by injected into your struct reverse in runtime. And this api will be then promoted to the root of struct reverse.
At the same time, this still allow inconsistency, where You have reverse struct instance with reverse.Interface = < Nil>, You compile it and get the panic on runtime.
When we look back to the specifically example of the reverse in OP, I can see it as a pattern, how you can replace/extend behaviour of some instance / implementation kind of in runtime contrary to working with types more like in compile time when You do embedding of structs instead of interfaces.
Still, it confuses me a lot. Especially the state where the Interface is Nil :(.

Resources