Instantiate generic interface with any, struct doesn't implement it - go

Can someone explain, why *DataTo does not satisfy ToType[any]?
Trying to build a DTOer, that copies all values of one struct to another and also sets some explicit values (V in this case)
https://go.dev/play/p/-oobZrw5Ewe
// You can edit this code!
// Click here and start typing.
package main
import "fmt"
type DataFrom struct {
V1 int
}
type DataTo struct {
V int
}
func (m *DataTo) SetVal() {
m.V = 1
return
}
type ToType[T any] interface {
SetVal()
*T
}
type DTO[TFrom any, TTo ToType[any]] struct {
Get func(from TFrom) TTo
}
func main() {
dto := &DTO[DataFrom, *DataTo]{
Get: func(from DataFrom) *DataTo {
return &DataTo{V: from.V1 + 666}
},
}
vFrom := DataFrom{V1: 1}
vTo := dto.Get(vFrom)
fmt.Println(vTo.V)
}

Because any is a static type.
If you use it to instantiate a generic type like ToType, that generic type will expect exactly any.
Now, certain usages of the type parameter might hide this issue, for example:
type Foo[T any] struct {
Value T
}
Foo[any]{Value: 12} // ok
Normally you are able to assign whatever type to any like the above, because any is just an alias of the empty interface interface{}, and any type satisfies the empty interface.
When the type parameter is used in composite types such as *T, then instantiating with any means exactly *any. Therefore you can imagine ToType[any] as the same thing as:
type ToTypeAny interface {
SetVal()
*any
}
And then *DataTo is obviously not *any. Further details: Assign struct pointer to interface pointer
If you declare the struct as follows it will compile:
type DTO[TFrom any, TTo ToType[DataTo]] struct {
Get func(from TFrom) TTo
}
Or in a more "generic" but also more verbose way:
type DTO[TFrom any, T any, TTo ToType[T]] struct {
Get func(from TFrom) TTo
}
&DTO[DataFrom, DataTo, *DataTo]{ ... }

Related

How can I set struct's fields of a generic type using Golang? [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: 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
}

how do I decouple my domain handler from package level definitions

I have a basic handler, that uses an 3rd party package messager.
The package returns a concrete struct of messager.Shape provided by a Get method.
messager.go
type Shape struct {
Value struct {
Type string
Other int
Active bool
}
Markers struct {
Range int
Name string
}
ID string
}
...
func (m *Messager) Get(ID string) (Shape, error) {
...
}
handler.go
package handler
import (
"fmt"
"github.com/fake/message"
)
type Getter interface {
Get(ID string) (messager.Shape, error)
}
type Handler struct {
messager Getter
}
func NewHandler(g Getter) *Handler {
return &Handler{ messager: g }
}
func (h *Handler) DoSomething() {
fmt.Println(h.messager.Get("some-id").Value.Type)
}
The handler only really cares that something can provide a struct with a matching nested Value.Type string.
I attempted defining a struct for the interface that wanted just:
type ValueType struct {
Value struct {
Type string
}
}
type Getter interface {
Get(ID string) (ValueType, error)
}
but the compiler rejects it when creating a NewHandler as the messager.Get method type does not match the interface. What am I suppose to do here? Is it appropriate for my Handler to reference the package struct? Should the package not be returning something so definitive?
I appreciate the example is a bit contrived but just trying to work out what's correct.

How can I find the root implementation of an interface in Go?

I have an interface RootInterface embedded in a struct OneConcrete. This concrete implementation of the interface is then embedded into another struct TwoConcrete as RootInterface again.
How do I determine that the actual implementation of RootInterface is OneConcrete? The following code hopefully shows what I am trying to achieve:
http://play.golang.org/p/YrwDRwQzDc
package main
import "fmt"
type RootInterface interface {
GetInt() int
}
type OneConcrete struct {
}
func (oc OneConcrete) GetInt() int {
return 1
}
type TwoConcrete struct {
RootInterface
}
func main() {
one := OneConcrete{}
fmt.Println("One", one.GetInt())
two := RootInterface(TwoConcrete{RootInterface: one})
_, ok := two.(TwoConcrete)
fmt.Println(ok) // prints true
// How can I get the equivalent of ok == true,
// i.e. find out that OneConcrete is the acutal
// RootInterface implementation?
_, ok = two.(OneConcrete)
fmt.Println(ok) // prints false
}
Note that I would like an answer to the general case where RootInterface could be embedded arbitrarily deeply within a struct hierarchy.
OneConcrete does not embeds interface. It implements that interface. Embedding a type mean that struct will get one additional field with same name as given type and all methods of that type will become methods of struct. So, to get OneConcrete you should do two.(TwoConcrete).RootInterface.(OneConcrete).

Resources