Embedding of mutually dependent structures/interfaces - go

I have 3 structures that are similar about 70%. So I'd like to extract some common part and create some extensions with specific methods and fields.
Final structure will work as follows:
method .Start() from Common is called
Start() calls method .Name() from specific part the latter return a string
the returned result is being processed in (*Common).Process(), sometimes it should call specific's Format()
But! Specific part have to call Common part's method, for example GetVerbosity()
Like this:
package common
type Common struct {
Specificer
}
func (c *Common) Start() {
...
name := Specific.Name()
}
func (c *Common) GetVerbosity() {...}
type Specificer interface {
Name() string
Format() string
}
And specific part:
package specific1
// should implement common.Specificer interface
type Specific1 struct {
// unexported fields
}
func (s *Specific1) Name() string {...}
func (s *Specific1) Format() string {
// How to call it???
Common.Method()
}
This is similar to some frameworks - when another code calls your code, and also you call it's code.
How to implement this better? And how to create new structures?
I tried:
Embed Specific to Common, and embed vise versa:
type Common struct {
Specificer
}
type Specific1 struct {
common.Common
...
}
// But this is little bit insane:
func NewSpecific1() *common.Common {
var s = Specific1{}
return &common.Common{Specificer: &s}
}
Define 2 interfaces: Commoner and Specificer. And combined interface:
package common
type CommonSpecificer interface {
Commoner
Specificer
}
type Common struct {...} // implements all the methods from Commoner
func New() *Common {...}
//////
package specific1
type Specific1 struct { // implements all the methods from common.Specificer
Common
...
}
func NewSpecific1() *Specific1 {
c := common.NewCommon(...)
s := &Specific1{Common: c}
return s
}

Related

Return an implementation of type-constrained interface from a function [duplicate]

I've just seen Go has incorporated generics in its latest release, and I'm trying to create a small project to understand how it works. I don't seem to figure out how it works apart from very simple functions being now generic. I'd like to be able to do things like this:
type Dao[RT any] interface {
FindOne(id string) *RT
}
type MyDao struct {
}
type ReturnType struct {
id int
}
func (m *MyDao) FindOne(id string) *ReturnType {
panic("implement me")
}
// how should this look like?
func NewMyDao() *Dao[ReturnType] {
return &MyDao[ReturnType]{}
}
Is that even possible? I don't seem to be implementing the interface that way, and I've tried many combinations of the same.
Is there a way to implement a generic interface? If not, is the alternative only to return the interface{} type?
Types don't actually implement generic interfaces, they implement instantiations of generic interfaces. You can't use a generic type (including interfaces) without instantiation. From there, it is just like pre-generics Go, including the difference between methods with pointer receiver.
Therefore it is helpful to think what the methods that use type parameters would look like if you rewrote them with concrete types.
Let's consider a generic interface and some type:
type Getter[T any] interface {
Get() T
}
type MyStruct struct {
Val string
}
There's a few possible cases
Interface with concrete type argument
Instantiate as Getter[string], implemented by types with method Get() string
// implements Getter[string]
func (m MyStruct) Get() string {
return m.Val
}
// ok
func foo() Getter[string] {
return MyStruct{}
}
Interface with type parameter as type argument
Functions that have type parameters may use those to instantiate generic types, e.g. Getter[T]. Implementors must have exactly the Get() T method. For that to be valid, they are also generic and instantiated with the same type parameter:
So this doesn't compile even if T is string
// Getter[T] literally needs implementors with `Get() T` method
func bar[T any]() Getter[T] {
return MyStruct{} // doesn't compile, even if T is string
}
Making MyStruct also parametrized works:
type MyStruct[T any] struct {
Val T
}
func (m MyStruct[T]) Get() T {
return m.Val
}
func bar[T any]() Getter[T] {
return MyStruct[T]{} // ok
}
Concrete interface with generic implementor
Let's reverse the previous cases. We keep the parametrized MyStruct[T any] but now the interface is not parametrized:
type Getter interface {
Get() string
}
In this case, MyStruct implements Getter only when it is instantiated with the necessary concrete type:
// Getter requires method `Get() string`
func baz() Getter {
return MyStruct[string]{} // instantiate with string, ok
// return MyStruct[int]{} // instantiate with something else, doesn't compile
}
Pointer receivers
This follows the same rules as above, but requires instantiating pointer types, as usual:
// pointer receiver, implements Getter[string]
func (m *MyStruct) Get() string {
return m.Val
}
func foo() Getter[string] {
return &MyStruct{} // ok
// return MyStruct{} // doesn't implement
}
and it is the same if MyStruct is generic.
// parametrized pointer receiver
func (m *MyStruct[T]) Get() T {
return m.Val
}
func foo() Getter[string] {
return &MyStruct[string]{} // ok
}
So in your case, the mental exercise of replacing the type params with concrete types gives that Dao[ReturnType] has method FindOne(id string) *ReturnType. The type that implements this method is *MyDao (pointer receiver), therefore:
func NewMyDao() Dao[ReturnType] {
return &MyDao{}
}
The type *MyDao implements the interface Dao[ReturnType]. Thus, the function should look like:
func NewMyDao() Dao[ReturnType] {
return &MyDao{}
}
Note that the return type is an instance of the generic interface, and the returned value is simply an instance of the *MyDao type.

How to implement two interfaces with same method name and different arguments

I have two different interfaces (from two different packages) that I want to implement. But they conflict, like this:
type InterfaceA interface {
Init()
}
type InterfaceB interface {
Init(name string)
}
type Implementer struct {} // Wants to implement A and B
func (i Implementer) Init() {}
func (i Implementer) Init(name string) {} // Compiler complains
It says "Method redeclared". How can one struct implement both interfaces?
As already answered, this is not possible since Golang does not (and probably will not) support method overloading.
Look at Golang FAQ:
Experience with other languages told us that having a variety of methods with the same name but different signatures was occasionally useful but that it could also be confusing and fragile in practice. Matching only by name and requiring consistency in the types was a major simplifying decision in Go's type system.
It is not possible.
In go you must have a single method signature.
You should rename one method.
The method signatures must match. If you want dependency injection I would recommend the functional option pattern. Functional options are functions that return other functions that are called in a loop in the constructor. Here is an example of how to use functional options and the basics of interfaces in go.
package main
import (
"fmt"
"strconv"
)
type SomeData struct {
data string
}
// SomeData and SomeOtherData both implement SomeInterface and SomeOtherInterface
// SomeInterface and SomeOtherInterface both implement each other.
type SomeInterface interface {
String() string
Set(data string)
}
func (s *SomeData)String() string {
return s.data
}
func (s *SomeData)Set(data string) {
s.data = data
}
// SetDataOption is a functional option that can be used to inject a constructor dep
func SetDataOption(data string) func(*SomeData) {
return func(s *SomeData) {
s.Set(data)
}
}
// NewSomeData is the constructor; it takes in 0 to many functional options and calls each one in a loop.
func NewSomeData(options ...func(s *SomeData)) SomeInterface {
s := new(SomeData)
for _, o := range options {
o(s)
}
return s
}
//********************
type SomeOtherData struct {
data string
i int
}
type SomeOtherInterface interface {
String() string
Set(data string)
}
func (s *SomeOtherData)String() string {
return s.data + " " + strconv.Itoa(s.i)
}
func (s *SomeOtherData)Set(data string) {
s.data = data
}
func SetOtherDataOption(data string) func(*SomeOtherData) {
return func(s *SomeOtherData) {
s.Set(data)
}
}
func SetOtherIntOption(i int) func(*SomeOtherData) {
return func(s *SomeOtherData) {
s.i = i
}
}
// NewSomeOther data works just like NewSomeData only in this case, there are more options to choose from
// you can use none or any of them.
func NewSomeOtherData(options ...func(s *SomeOtherData)) SomeOtherInterface {
s := new(SomeOtherData)
for _, o := range options {
o(s)
}
return s
}
//*********************************
// HandleData accepts an interface
// Regardless of which underlying struct is in the interface, this function will handle
// either by calling the methods on the underlying struct.
func HandleData(si SomeInterface) {
fmt.Println(si) // fmt.Println calls the String() method of your struct if it has one using the Stringer interface
}
func main() {
someData := NewSomeData(SetDataOption("Optional constructor dep"))
someOtherData := NewSomeOtherData(SetOtherDataOption("Other optional constructor dep"), SetOtherIntOption(42))
HandleData(someData) // calls SomeData.String()
HandleData(someOtherData) // calls SomeOtherData.String()
someOtherData = someData // assign the first interface to the second, this works because they both implement each other.
HandleData(someOtherData) // calls SomeData.String() because there is a SomeData in the someOtherData variable.
}

How to implement generic interfaces?

I've just seen Go has incorporated generics in its latest release, and I'm trying to create a small project to understand how it works. I don't seem to figure out how it works apart from very simple functions being now generic. I'd like to be able to do things like this:
type Dao[RT any] interface {
FindOne(id string) *RT
}
type MyDao struct {
}
type ReturnType struct {
id int
}
func (m *MyDao) FindOne(id string) *ReturnType {
panic("implement me")
}
// how should this look like?
func NewMyDao() *Dao[ReturnType] {
return &MyDao[ReturnType]{}
}
Is that even possible? I don't seem to be implementing the interface that way, and I've tried many combinations of the same.
Is there a way to implement a generic interface? If not, is the alternative only to return the interface{} type?
Types don't actually implement generic interfaces, they implement instantiations of generic interfaces. You can't use a generic type (including interfaces) without instantiation. From there, it is just like pre-generics Go, including the difference between methods with pointer receiver.
Therefore it is helpful to think what the methods that use type parameters would look like if you rewrote them with concrete types.
Let's consider a generic interface and some type:
type Getter[T any] interface {
Get() T
}
type MyStruct struct {
Val string
}
There's a few possible cases
Interface with concrete type argument
Instantiate as Getter[string], implemented by types with method Get() string
// implements Getter[string]
func (m MyStruct) Get() string {
return m.Val
}
// ok
func foo() Getter[string] {
return MyStruct{}
}
Interface with type parameter as type argument
Functions that have type parameters may use those to instantiate generic types, e.g. Getter[T]. Implementors must have exactly the Get() T method. For that to be valid, they are also generic and instantiated with the same type parameter:
So this doesn't compile even if T is string
// Getter[T] literally needs implementors with `Get() T` method
func bar[T any]() Getter[T] {
return MyStruct{} // doesn't compile, even if T is string
}
Making MyStruct also parametrized works:
type MyStruct[T any] struct {
Val T
}
func (m MyStruct[T]) Get() T {
return m.Val
}
func bar[T any]() Getter[T] {
return MyStruct[T]{} // ok
}
Concrete interface with generic implementor
Let's reverse the previous cases. We keep the parametrized MyStruct[T any] but now the interface is not parametrized:
type Getter interface {
Get() string
}
In this case, MyStruct implements Getter only when it is instantiated with the necessary concrete type:
// Getter requires method `Get() string`
func baz() Getter {
return MyStruct[string]{} // instantiate with string, ok
// return MyStruct[int]{} // instantiate with something else, doesn't compile
}
Pointer receivers
This follows the same rules as above, but requires instantiating pointer types, as usual:
// pointer receiver, implements Getter[string]
func (m *MyStruct) Get() string {
return m.Val
}
func foo() Getter[string] {
return &MyStruct{} // ok
// return MyStruct{} // doesn't implement
}
and it is the same if MyStruct is generic.
// parametrized pointer receiver
func (m *MyStruct[T]) Get() T {
return m.Val
}
func foo() Getter[string] {
return &MyStruct[string]{} // ok
}
So in your case, the mental exercise of replacing the type params with concrete types gives that Dao[ReturnType] has method FindOne(id string) *ReturnType. The type that implements this method is *MyDao (pointer receiver), therefore:
func NewMyDao() Dao[ReturnType] {
return &MyDao{}
}
The type *MyDao implements the interface Dao[ReturnType]. Thus, the function should look like:
func NewMyDao() Dao[ReturnType] {
return &MyDao{}
}
Note that the return type is an instance of the generic interface, and the returned value is simply an instance of the *MyDao type.

Can an interface method accept/return a struct while allowing the use of structs with the same shape to satisfy it?

I would like to create a library that exports a function that defines its own dependencies without consuming types from an external package (excluding std lib).
The issue is, if my dependency is an interface type with a method that returns a struct, consumers have to use the exact struct declared in the interface.
In situations where I have two or more libraries, each sharing the same interface signature however each package defining its own interface (interface segregation), they conflict when it comes to methods that return struct types.
package mylibrary
type Result struct {
Value string
}
type IFoo interface {
Foo() Result
}
func DoFoo(f IFoo) {
f.Foo()
}
With the above code, anyone implementing this library must use the mylibrary.Result struct exactly to satisfy the IFoo interface.
In the case where I have multiple packages defining the interfaces of their own dependencies, this can become difficult and or impossible
See the following example: https://replit.com/#davidalsh/UsedCarefreeBrain#main.go
// main.go
// Creating an object that satisfies the contract roughly
import (
packagea "main/package-a"
packageb "main/package-b"
)
type Result struct {
Message string
}
type Foo struct {}
// Even though Result is the same shape, this needs to
// return either packagea.Result or packageb.Result
func (*Foo) Foo() Result {
return Result{}
}
func main() {
dep := Foo{}
packagea.DoFoo(dep) // Foo does not implement packagea.IFoo
packageb.DoFoo(dep) // Foo does not implement packageb.IFoo
}
This seems like a strange limitation. Methods on an interface can return types like string, int, []int, etc but not a struct.
Should I be returning an interface with getters/setters from IFoo.Foo, e.g.?
type IResult interface {
Message() string
}
type IFoo interface {
Foo() IResult
}
What if I would like to use a struct as an argument for a function? Should I also only accept an interface of getters?
interface IUserDetails {
FirstName() string
LastName() string
Age() int
}
func SayHello(user IUserDetails) {
fmt.Println("Hello", user.FirstName())
}
Or is there a better way?
Define a type in a third package:
common/common.go
package common
type Result struct {
Message string
}
Use this package in all other packages:
main.go
package main
import (
"main/common"
packagea "main/package-a"
packageb "main/package-b"
)
type Foo struct{}
func (*Foo) Foo() common.Result {
return common.Result{}
}
func main() {
dep := &Foo{}
packagea.DoFoo(dep)
packageb.DoFoo(dep)
}
package-a/packagea.go
package packagea
import "main/common"
type IFoo interface {
Foo() common.Result
}
func DoFoo(f IFoo) {
f.Foo()
}
Run the program on the Go Lang Playground

Golang return child struct in place of parent like in c++

I am trying to have a generic function that can return various multiple child objects. The idea is to be able to return those in a request json body.
The code is as follows
GenericType struct {
V1 string `json:"v1"`
V2 string `json:"v2"`
}
SubType struct {
GenericType
V3 string `json:"v3"`
}
func TestFunc() GenericType {
val := SubType{
GenericType: GenericType{
V1: "a",
V2: "b",
},
V3: "c",
}
return val
}
The error is
cannot use val (type SubType) as type GenericType in return argument
Is it possible to return a descendant struct in a parent pointer without losing the fields of that descendant struct and then return it as a JSON object in response body?
You can't use embedding as a substitute for inheritance. You could use interfaces for that though. Something like:
type Generic interface {
V1() string
V2() string
}
type parent struct {
// ...
}
type child struct {
// ...
}
// parent
func (p *parent) V1() string {
return "parent V1"
}
func (p *parent) V2() string {
return "parent V2"
}
// child
func (c *child) V1() string {
return "child V1"
}
func (c *child) V2() string {
return "child V2"
}
// further child methods
func NewGeneric() Generic {
return &parent{}
// or
// return &child{}
}
Go does not have inheritance (like C++ or Java), but only composition and interfaces. So your function could return only one type structure (or pointer) or interface. As a first approximation you could think that interface is nearly the same as pure abstract class in C++).
In your case interface is better. And now it depends how rest of the program will work with returned value. If it need to call a few methods (in go we prefer interface with only few method - ideal is one).
Eg.
type GenericType interface {
getV1() string
getV2() string
}
But unfortunately - for all object that could be serialized into JSON we don't have any common method (eg. int, string or arrays), therefore we have to use interface with no common method - interface{}.
Embedding
Embedding in Go doesn't allow to inherit (since it is not inheritance) attributes. When you are embedding one struct to another you are composing its' methods (not attributes) to a new composition.
Go does not provide the typical, type-driven notion of subclassing, but it does have the ability to “borrow” pieces of an implementation by embedding types within a struct or interface.
Interfaces
Go provides awesome interfaces to implement generic types and type assertion to have access to concrete types and its' attributes.
Plyground:
type generic interface {
say() string
}
type type1 struct {
msg string
}
func (t type1) say() string {
return t.msg
}
type type2 struct{}
func (t type2) say() string {
return "I'm type 2"
}
func main() {
t1 := type1{"Hey! I'm type1"}
t2 := type2{}
tl := []generic{t1, t2}
for _, i := range tl {
switch v := i.(type) {
case type1:
fmt.Println(v.say())
fmt.Println(v.msg)
case type2:
fmt.Println(v.say())
// fmt.Println(v.msg) Uncomment to see that type2 has no msg attribute.
}
}
}

Resources