Collections of generic structs with embedded locks in golang - go

Below I have an example of one structure which embeds another. I'm trying to figure out how to pass the more specific structure pointer to be stored in a less specific one. You can think of it as a collection. Wrapping in an interface doesn't seem to work, as doing so would make a copy, which isn't valid for structs with locks. Ideas?
package stackoverflow
import "sync"
type CoolerThingWithLock struct {
fancyStuff string
ThingWithLock
}
func NewCoolerThingWithLock() *CoolerThingWithLock {
coolerThingWithLock := &CoolerThingWithLock{}
coolerThingWithLock.InitThingWithLock()
return coolerThingWithLock
}
type ThingWithLock struct {
value int
lock sync.Mutex
children []*ThingWithLock
}
func (thingWithLock *ThingWithLock) InitThingWithLock() {
thingWithLock.children = make([]*ThingWithLock, 0)
}
func NewThingWithLock() *ThingWithLock {
newThingWithLock := &ThingWithLock{}
newThingWithLock.InitThingWithLock()
return newThingWithLock
}
func (thingWithLock *ThingWithLock) AddChild(newChild *ThingWithLock) {
thingWithLock.children = append(thingWithLock.children, newChild)
}
func (thingWithLock *ThingWithLock) SetValue(newValue int) {
thingWithLock.lock.Lock()
defer thingWithLock.lock.Unlock()
thingWithLock.value = newValue
for _, child := range thingWithLock.children {
child.SetValue(newValue)
}
}
func main() {
thingOne := NewThingWithLock()
thingTwo := NewCoolerThingWithLock()
thingOne.AddChild(thingTwo)
thingOne.SetValue(42)
}
Error: cannot use thingTwo (type *CoolerThingWithLock) as type
*ThingWithLock in argument to thingOne.AddChild

It's impossible to store the wrapping type in []*ThignWithLock since go has no notion of structural subtyping.
Your assertion that an interface will result in copying is incorrect, and you can get the desired effect by doing:
type InterfaceOfThingThatParticipatesInAHierarchy interface {
AddChild(InterfaceOfThingThatParticipatesInAHierarchy)
SetValue(int)
}
type ThingWithLock struct {
...
children []InterfaceOfThingThatParticipatesInAHierarchy
}
func (thingWithLock *ThingWithLock) AddChild(newChild InterfaceOfThingThatParticipatesInAHierarchy) { ... }
As long as the interface is implemented on a *ThingWithLock and not ThingWithLock, there will be no copying of the receiver struct itself, only the pointer to the struct will be copied on the stack.

Related

Passing struct array with anonymous field in Go

this question is related to Passing struct with anonymous field in Go but different in that I am dealing with a function that handles an array of Parent items rather than just one struct, ie:
package main
import "fmt"
type Parent struct {
Dad string
}
type Child struct {
Parent
Son string
}
func myfunc(data []Parent) {
for n, _ := range data {
fmt.Printf("Dad is %s\n", data[n].Dad)
}
}
func main() {
data := make([]Child, 2)
data[0].Dad = "pappy"
data[0].Son = "sonny"
data[1].Dad = "daddy"
data[1].Son = "billy"
myfunc(data)
}
I tried to cast data to an array of Parents like myfunc([]Parent(data)) but that didnt work and obviously the solution of myfunc(data.Parent) wont work on an array.
Is there a reasonable solution to this in golang without resorting to creating a new slice or generics which are not out of beta yet?
Cheers
You cannot do this even with generics. data[n].Dad will not work.
The reasonable way to deal with it is to use an interface, but still, you have to create an interface slice for it:
type WithDad interface {
GetDad() string
}
func (p Parent) GetDad() string {return p.Dad}
func myFunc(data []WithDad) {
...
}
...
arr:=make([]WithDad,0,len(data))
for _,x:=range data {
arr=append(arr,x)
}
myFunc(arr)
The reason for this is how the type system works and how slices are passed around. The slice []Child points to an array where each entry is a Child. A function that takes []Parent expects a slice whose elements are Parent, which is a different type, so you cannot pass one for the other.
The slice []WithDad points to an array where each entry is an interface. Each such entry points to the Child or Parent entry in another slice.
Just for completeness I made a complete version of Burak Serdar code I got working (I like it when full working examples are posted for me to cut and paste later :P) ... note I deliberately return a pointer to the Parent because in practice its likely you will want to work on that complete struct and not just read 1 field.
package main
import "fmt"
type WithDad interface {
GetDad() *Parent
}
type Parent struct {
Dad string
}
func (p *Parent) GetDad() *Parent {
return p
}
type Child struct {
Parent
Son string
}
func (c *Child) GetDad() *Parent {
return &c.Parent
}
func myfunc(data []WithDad) {
for n, _ := range data {
fmt.Printf("Dad is %s\n", data[n].GetDad().Dad)
}
}
func main() {
data := make([]WithDad, 2)
data[0] = &Child{Parent: Parent{Dad: "pappy"}, Son: "sonny"}
data[1] = &Child{Parent: Parent{Dad: "daddy"}, Son: "billy"}
myfunc(data)
}
Your structure with Child being a composite of Parent and a string (which I guess contains the name) makes little sense. A child is not a parent plus their name. In fact you only have one concept, namely Person, who potentially has a parent. Please consider the following approach:
package main
import "fmt"
type Person struct {
Name string
Parent *Person
}
func myfunc(data []Person) {
for n, _ := range data {
fmt.PrintLn("My name is", n.Name)
if n.Parent != nil {
fmt.PrintLn("My dad is", n.Parent.Name)
}
}
}
func main() {
data := make([]Person, 2)
data[0].Name = "daddy"
data[1].Name = "billy"
data[1].Parent = &data[0]
myfunc(data)
}

Effectively wrapping public sdk types in golang

I am using pagerduty go sdk to do a bunch of api requests.
Particularly I am making use of
func NewClient(authToken string) *Client
to create a new Client type. I want to add some utility functions to my own work to *Client. I tried doing this:
type BetterPdClient *pagerduty.Client
func NewClient(auth string) BetterPdClient {
return pagerduty.NewClient(auth)
}
func (b *BetterPdClient) DoSomething() {
b.GetIncident(....)
}
func main() {
pd_client := NewClient("")
fmt.Println(pd_client)
pd_client.DoSomething()
}
But I get the following error:
invalid receiver type *BetterPdClient (BetterPdClient is a pointer type)
I understand that DoSomething() is expecting a pointer as caller. Only other way I could think of is sending the ptr as a function argument:
func NewClient(auth string) *pagerduty.Client {
return pagerduty.NewClient(auth)
}
func DoSomething(cl *pagerduty.Client) {
fmt.Println(cl)
}
func main() {
pd_client := NewClient("")
fmt.Println(pd_client)
DoSomething(pd_client)
}
Is there a better way?
Declaring a type as a pointer to another type is almost never what you want because Go doesn't allow you to add methods to that new type, nor to the pointer of that type as you've already figured out yourself. This one doesn't compile either:
type T struct{}
type P *T
func (P) M() {}
If you want to "extend" a type without "hiding" it's existing functionality your best bet is to embed it in a struct.
type T struct{
// ...
}
func (T) M() {}
type U struct {
*T
}
func NewU() *U {
return &U{&T{}}
}
func (U) N() {}
func main() {
u := NewU()
u.M()
u.N()
}
And what I mean by "hiding existing functionality" is that when you define a new type in terms of another, already existing type, your new type will not get direct access to the methods of the existing type. All you're doing is just saying that your new type should have the same structure as the already existing type. Although it's worth pointing out that this property gives you the ability to convert one type to the other...
type T struct{
// ...
}
func (T) M() {}
type U T
func NewU() *U {
return &U{}
}
func (U) N() {}
func main() {
u := NewU()
u.M() // compile error
u.N()
// convert *U to *T and then call M
(*T)(u).M()
}

range over an []interfaces{} and get the channel field of each type

I'll try to make it as clear as possible, in my head first.
I have an interface and a couple of Types that inherit it by declaring a method. Pretty nice and clever way of inheritance.
I have then a "super" Type Thing, which all the other Types embed.
The Thing struct has a Size int and an Out chan properties
What I'm trying to understand is why I can get the value of size .GetSize() from both the child structs, but I don't have the same success with the channel field .GetChannel() (*ndr which I'm using to communicate among goroutines and their caller)
...here I get t.GetChannel undefined (type Measurable has no field or method GetChannel)
It might help a demo of the logic:
package main
import (
"fmt"
)
type Measurable interface {
GetSize() int
}
type Thing struct {
Size int
Out chan int
}
type Something struct{ *Thing }
type Otherthing struct{ *Thing }
func newThing(size int) *Thing {
return &Thing{
Size: size,
Out: make(chan int),
}
}
func NewSomething(size int) *Something { return &Something{Thing: newThing(size)} }
func NewOtherthing(size int) *Otherthing { return &Otherthing{Thing: newThing(size)} }
func (s *Thing) GetSize() int { return s.Size }
func (s *Thing) GetChannel() chan int { return s.Out }
func main() {
things := []Measurable{}
pen := NewSomething(7)
paper := NewOtherthing(5)
things = append(things, pen, paper)
for _, t := range things {
fmt.Printf("%T %d \n", t, t.GetSize())
}
for _, t := range things {
fmt.Printf("%+v \n", t.GetChannel())
}
// for _, t := range things {
// fmt.Printf("%+v", t.Thing.Size)
// }
}
The commented code is another thing I'm trying to learn. I can get a value by using a method declared on the super Type, but not by accessing directly from the child one. Sure, I could resolve the type with t.(*bothTheThingTypes).Size but I lose the dinamicity, I'm not fully getting this...
What I'm trying to understand is why I can get the value of size
.GetSize() from both the child structs, but I don't have the same
success with the channel field .GetChannel()
type Measurable interface {
GetSize() int
}
...
things := []Measurable{}
for _, t := range things {
fmt.Printf("%+v \n", t.GetChannel())
}
I may be missing the point but this seems to be caused strictly by the fact that your Measurable interface doesn't have a GetChannel method.

how to get the method fields of a typed function (Go)

I'm wondering if it's possible to get the method fields from a typed function using reflection or by other means.
The problem that I'm trying to solve is that I have a method which accepts a function of specific type but I need to actually transport different types and based on the type provided to execute operations. I'm aware that I could use an interface{} value as receiver but I don't want to loose the type checking on the calling function ("GetIt")
package main
type ttp struct {
Coupons string
}
func (m ttp) GetIt(x string) {
if m.Coupons != "" {
print(m.Coupons)
}
}
func calculate(mth func(s string)){
//perform calculations and update the Coupon field
mth.Cupons = "one coupon" // is not working :(
// execute it again with the processed value
mth.GetIt() // is not working
}
func main() {
m := ttp{Coupons: "something"}
calculate(m.GetIt)
}
Play
well this does not answer your exact question but it should solve your problem and cleanup the logic: push the calculate method inside the type and use a interface
https://play.golang.org/p/On_AigRYW6
package main
import "fmt"
type Computer interface {
Compute(string)
}
type myp struct {
Coupons string
}
// myp implements Computer
func (m *myp) Compute(x string) {
m.GetIt(x)
fmt.Println("myp")
}
type ttp struct {
Various string
}
// ttp implements Computer
func (m *ttp) Compute(x string) {
m.GetIt(x)
fmt.Println("ttp")
}
func (m myp) GetIt(x string) {}
func (m ttp) GetIt(x string) {}
func main() {
m := &myp{Coupons: "something"}
t := &ttp{Various: "various stuff"}
var stuff = []Computer{m, t}
for _, c := range stuff {
c.Compute("s")
}
}

Go: Am I creating too many values?

If I have a struct like this
type myStruct struct {
mystring string
myint int
}
and if I have a function that returns a new myStruct like this
func New() myStruct {
s := myStruct{}
s.mystring = "string"
s.myint = 1
return s
}
Because I first store it in the "s" variable before returning it, is my function actually making 2 myStruct values instead of one?
And if so, is it then a better practice to make sure I don't first store it in the variable?
The return statement will return a copy of the myStruct object value. If it is a small object then this is fine.
If you intend for the caller to be able to modify this object, and the struct will have methods that use a pointer as the receiver, then it makes more sense to return a pointer to your struct instead:
func New() *myStruct {
s := myStruct{}
s.mystring = "string"
s.myint = 1
return &s
}
You can see the copy happening when you compare the memory address of value vs pointer return types: http://play.golang.org/p/sj6mivYSHg
package main
import (
"fmt"
)
type myStruct struct {
mystring string
myint int
}
func NewObj() myStruct {
s := myStruct{}
fmt.Printf("%p\n", &s)
return s
}
func NewPtr() *myStruct {
s := &myStruct{}
fmt.Printf("%p\n",s)
return s
}
func main() {
o := NewObj()
fmt.Printf("%p\n",&o)
p := NewPtr()
fmt.Printf("%p\n",p)
}
0xf8400235a0 // obj inside NewObj()
0xf840023580 // obj returned to caller
0xf840023640 // ptr inside of NewPtr()
0xf840023640 // ptr returned to caller
I'm definitely not a Go expert (or even novice :) ), but as #max.haredoom mentioned, you can allocate variables in the function signature itself. In that way, you can also omit the s in the return:
package main
import "fmt"
type myStruct struct {
mystring string
myint int
}
func New() (s myStruct) {
s.mystring = "string"
s.myint = 1
return
}
func main() {
r := New()
fmt.Println(r)
}
// Outputs {string 1}
In the examples that I have come across in Effective Go, it does seem to be the most common way of doing things of this nature, but again, I am definitely not an authority on the subject (and will look for additional info on the actual performance).
I think I found the answer by using defer.
I updated the function so that there's a deferred modification to the myStruct value. This means it will happen after the return, but before it is received on the other end.
When I do this, the struct that is received by the caller does not show the updated value, so it appears as though I am indeed returning a copy.
func New() myStruct {
s := myStruct{}
defer func() {
s.mystring = "new value" // defer an update to the value
}()
s.mystring = "string"
s.myint = 1
return s
}
func main() {
b := New()
fmt.Println(b) // still shows the original value
}
http://play.golang.org/p/WWQi8HpDny

Resources