-2

Given an interface that returns a slice of pointer types but wrapped as an interface type. Is it possible to modify the values?

type Base interface {
    Do()
}

type Meta interface {
    Base
    Children() []Base
}

type A struct {
}

func (a *A) Do() {
}

type B struct {
    children []Base
}

func (b *B) Children() []Base {
    return b.children
}

If the code is initialized in the following way:

a := &A{}
b := &B{children: []Base{a}}

would it be possible to overwrite the values at B.children just with the values returned after calling b.Children() and the use of reflect? Or would that not be possible?

https://play.golang.net/p/rvMsdVNLQ6a

Mahoni
  • 7,088
  • 17
  • 58
  • 115
  • That makes sense but if the implementer decides to return a newly allocated slice it would be build on failed assumptions. Post it as an answer so I can accept it? – Mahoni Jul 27 '21 at 01:24
  • 2
    Why not add a method to set children in `Meta` interface? – advay rajhansa Jul 27 '21 at 01:43
  • @advayrajhansa Great suggestion, I have been thinking about it but sometimes the children elements are not stored as a slice but instead just a few separate elements in the struct, then it becomes a lot harder to set up an interface that will work: get and set children need to set and return them in the same order for instance. – Mahoni Jul 27 '21 at 02:06
  • 1
    In the given context, I would argue that `interfaces` are not the way to go ahead. If you directly need the definite struct (which is definitely possible using reflection if you need), then I think it is better not to wrap this with interface. Unsure of the complete picture, I think factory patter could help. If not, reflect is there to help. – advay rajhansa Jul 27 '21 at 02:44
  • The moment you started trying to mimik inheritance of traditional OOP you started to fail. There is absolutely no way to get an kind of inheritance to work in Go. – Volker Jul 27 '21 at 05:30

1 Answers1

0

The interface method Children() []Base returns a copy of the slice header from the underlying structure. You can modify the elements of the slice, but you cannot modify the slice included in the object referenced by the interface.

If you have a variable of type Meta, you can use type assertion to check if the underlying object is a *B, and if so, access children directly from the same package.

One way to change the slice is to add another interface to do just that:

type childrenSetter interface {
   SetChildren([]Base)
}

...
if setter, ok:=intf.(childrenSetter); ok {
   setter.SetChildren(newChildren)
}

This will work only if the underlying type implements SetChildren method.

Burak Serdar
  • 46,455
  • 3
  • 40
  • 59