Assign struct pointer to interface pointer - go

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())
}

Related

Golang: Generic struct receiver gets error: undefined (type T has no field or method) [duplicate]

I would like to make the following code compile. My understanding from reading the Type Parameters Proposal (Go Generics) is that this should work, but I must be missing something.
package main
import "fmt"
func main() {
s := Struct{A: "Hello World!"}
PrintA(s)
}
func PrintA[T Type](v T) {
fmt.Printf("%s\n", v.A)
}
type Type interface {
struct{ A string }
}
type Struct struct {
A string
}
func (s Struct) String() string {
return s.A
}
The error I get is:
./prog.go:7:8: Struct does not implement Type (possibly missing ~ for struct{A string} in constraint Type)
./prog.go:11:23: v.A undefined (type T has no field or method A)
I would like T to represent all structs with a particular field of a particular type. Adding ~ did not help.
Here's an example from the proposal that was implemented and is part of the latest Go beta release.
type structField interface {
struct { a int; x int } |
struct { b int; x float64 } |
struct { c int; x uint64 }
}
https://go.dev/play/p/KZh2swZuD2m?v=gotip
Field access has been disabled for Go 1.18 (still disabled in Go 1.19). The Go 1.18 release notes mention this:
The current generics implementation has the following known limitations:
[...]
The Go compiler does not support accessing a struct field x.f where x is of type parameter type even if all types in the type parameter's type set have a field f. We may remove this restriction in Go 1.19.
The workaround for any struct type boils down to old boring interface-based polymorphism:
type Type interface {
GetA() string
}
func (s Struct) GetA() string {
return s.A
}
And at this point you don't even have to use the Type interface as a constraint. It can just be a plain interface type:
func PrintA(v Type) {
fmt.Printf("%s\n", v.GetA())
}
If you are ok with using this interface only as a constraint, you may add type elements to restrict which structs can implement it:
type Type interface {
StructFoo | StructBar
GetA() string
}
Use pointer types if you declared the methods with pointer receiver.
Old answer (not relevant anymore, only informative)
At some point in early 2022 while this feature was still in development, your example did work if you added ~:
type Type interface {
~struct{ A string }
}
but it only worked for structs exactly defined as struct{ A string } and nothing else. Defining a constraint that "represent[s] all structs with a particular field of a particular type" was never supported all along. See this answer for details.
Instead the example you quote from the proposal is about accessing a common field in a type set. By defining a union of structs:
type structField interface {
~struct { a int; x int } | ~struct { a int; x float64 }
}
you should be able to access the field a of such a type parameter, but again this wasn't implemented, as mentioned at the beginning of the answer. It used to work if all terms in the union had the same underlying type (example adapted from issue #48522).
This code doesn't compile anymore as of March 2022:
package main
import "fmt"
type Point struct {
X, Y int
}
type Rect struct {
X, Y int
}
func GetX[P Point | Rect] (p P) int {
return p.X
}
func main() {
p := Point{1, 2}
r := Rect{2, 3}
fmt.Println("X: %d %d", GetX(p), GetX(r)) // prints X: 1 2
}

Golang: Implement Interface with method that accepts argument of union type [duplicate]

I would like to make the following code compile. My understanding from reading the Type Parameters Proposal (Go Generics) is that this should work, but I must be missing something.
package main
import "fmt"
func main() {
s := Struct{A: "Hello World!"}
PrintA(s)
}
func PrintA[T Type](v T) {
fmt.Printf("%s\n", v.A)
}
type Type interface {
struct{ A string }
}
type Struct struct {
A string
}
func (s Struct) String() string {
return s.A
}
The error I get is:
./prog.go:7:8: Struct does not implement Type (possibly missing ~ for struct{A string} in constraint Type)
./prog.go:11:23: v.A undefined (type T has no field or method A)
I would like T to represent all structs with a particular field of a particular type. Adding ~ did not help.
Here's an example from the proposal that was implemented and is part of the latest Go beta release.
type structField interface {
struct { a int; x int } |
struct { b int; x float64 } |
struct { c int; x uint64 }
}
https://go.dev/play/p/KZh2swZuD2m?v=gotip
Field access has been disabled for Go 1.18 (still disabled in Go 1.19). The Go 1.18 release notes mention this:
The current generics implementation has the following known limitations:
[...]
The Go compiler does not support accessing a struct field x.f where x is of type parameter type even if all types in the type parameter's type set have a field f. We may remove this restriction in Go 1.19.
The workaround for any struct type boils down to old boring interface-based polymorphism:
type Type interface {
GetA() string
}
func (s Struct) GetA() string {
return s.A
}
And at this point you don't even have to use the Type interface as a constraint. It can just be a plain interface type:
func PrintA(v Type) {
fmt.Printf("%s\n", v.GetA())
}
If you are ok with using this interface only as a constraint, you may add type elements to restrict which structs can implement it:
type Type interface {
StructFoo | StructBar
GetA() string
}
Use pointer types if you declared the methods with pointer receiver.
Old answer (not relevant anymore, only informative)
At some point in early 2022 while this feature was still in development, your example did work if you added ~:
type Type interface {
~struct{ A string }
}
but it only worked for structs exactly defined as struct{ A string } and nothing else. Defining a constraint that "represent[s] all structs with a particular field of a particular type" was never supported all along. See this answer for details.
Instead the example you quote from the proposal is about accessing a common field in a type set. By defining a union of structs:
type structField interface {
~struct { a int; x int } | ~struct { a int; x float64 }
}
you should be able to access the field a of such a type parameter, but again this wasn't implemented, as mentioned at the beginning of the answer. It used to work if all terms in the union had the same underlying type (example adapted from issue #48522).
This code doesn't compile anymore as of March 2022:
package main
import "fmt"
type Point struct {
X, Y int
}
type Rect struct {
X, Y int
}
func GetX[P Point | Rect] (p P) int {
return p.X
}
func main() {
p := Point{1, 2}
r := Rect{2, 3}
fmt.Println("X: %d %d", GetX(p), GetX(r)) // prints X: 1 2
}

Why the init of interface could make an error

I mean the interface could even contain a composite type like struct
type A struct {
}
func main() {
var a interface{} = A{}
}
Its weird that interface cant initialize by the brace below this.
type C interface {
}
func main() {
_ = C{}
}
Compile result here:invalid composite literal type C
C is an interface type and therefore cannot be initialized with a composite literal.
Composite literals construct values for structs, arrays, slices, and
maps and create a new value each time they are evaluated.
https://golang.org/ref/spec#Composite_literals
To make the code compile you could do this:
type C interface {
}
func main() {
_ = C(nil)
}

Pass struct for function that accepts a interface

I have the following code:
package main
type MyInterface interface {
Test()
}
type MyType struct {
}
func (m MyType) Test(){}
func AcceptInterface(i *MyInterface){
}
func main() {
object := &MyType{}
AcceptInterface(object)
}
I was expecting this to work, because MyType implements MyInterface, but I get:
cannot use object (type *MyType) as type *MyInterface in argument to
AcceptInterface: *MyInterface is pointer to interface, not interface
I tried doing type assertion: object.(MyInterface), but that doesn't work either.
How can I accomplish this?
As the error says,
cannot use object (type *MyType) as type *MyInterface in argument to AcceptInterface: *MyInterface is pointer to interface, not interface
This means that it is expecting an interface value, not a pointer.
If you change the pointers to values in your code (by removing the & and *), the program will run with no errors:
package main
type MyInterface interface {
Test()
}
type MyType struct {
}
func (m MyType) Test(){}
func AcceptInterface(i MyInterface){
}
func main() {
object := MyType{}
AcceptInterface(object)
}
Play it
Edit 1
If you still want to use a pointer as an argument, there are two important parts of the Go language to note
From the Go Spec on what exacly is a variable that fits an instance:
A variable of interface type can store a value of any type with a method set that is any superset of the interface.
From the Go Spec on what pointers being automatically dereferenced:
As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: pt.Mv is equivalent to (*pt).Mv [and] as with method calls, a reference to a non-interface method with a pointer receiver using an addressable value will automatically take the address of that value: t.Mp is equivalent to (&t).Mp.
Those two points are important, because when combined they explain that pointers to variables can still fit instances. This is because the pointer's method set is automatically dereferenced by the Go compiler (and since the variable it is referencing can fit an instance, the pointer can, too)!
In action, this means that in order to see if a pointer fits an instance, you have to declare the instance as a value and the pointer as a pointer.
If you run this code:
package main
type MyInterface interface {
Test()
}
type MyType struct {
}
func (m MyType) Test() {}
func AcceptInterface(i MyInterface) {
}
func main() {
object := &MyType{}
AcceptInterface(object)
}
Play it
you will see that there are no errors! Notice how there is an & in the object declaration, but no * in the i declaration?
type MyInterface interface {
Test()
}
type MyType struct {
}
func (m MyType) Test(){}
Note: it means that MyType implemts the interface MyInterface, not MyType*.
You can use:
func (m *MyType) Test(){} //Notice here
func AcceptInterface(i *MyInterface){
}
func main() {
object := &MyType{}
AcceptInterface(object)
}
Use explicit typing if you want to pass a pointer to interface:
func main() {
var object MyInterface = MyType{}
AcceptInterface(&object)
}
I would not recommend using pointer interfaces as you would need to write code like (*i).Test() to call the interface pointer methods. The compiler do auto dereferencing for struct pointers, not so for interface pointers.

Polymorphism in Go - does it exist?

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.

Resources