Type to base ,type lost

package main

import (
“fmt”
)

type IComponent interface {
GetParent() IComponent
SetParent(parent IComponent)
Tick()
}

type IUpdatable interface {
Update()
}

type Component struct {
Name string
Parent IComponent
}

func (c *Component) GetParent() IComponent {
return c.Parent
}

func (c *Component) SetParent(parent IComponent) {
c.Parent = parent
}

func (c *Component) AddChild(child IComponent) {
child.SetParent(c)

//other

}

func (c *Component) Tick() {
fmt.Println(“base Tick”)
}

type ComponentA struct {
Component
}

type ComponentB struct {
Component
}

func (c *ComponentB) Update() {
fmt.Println(“ComponentB Update”)
}

func (c *ComponentB) Tick() {
fmt.Println(“ComponentB Tick”)
c.Update()
}

func init() {

}

func RunComponent1() {
fmt.Println(“#####################RunComponent1##################################”)
child := new(ComponentA)
child.Name = “child”

parent := new(ComponentB)
parent.Name = "parent"
parent.AddChild(child)
parent.Tick()

var updater1 IUpdatable = parent
updater1.Update()

a1Parent := child.GetParent()
if a1Parent == parent {
	fmt.Println("==")
}
a1Parent.Tick()

updater2, ok := a1Parent.(IUpdatable)
if ok {
	updater2.Update()
}

}

func RunComponent2() {
fmt.Println(“#####################RunComponent2##################################”)
child := new(ComponentA)
child.Name = “child”

parent := new(ComponentB)
parent.Name = "parent"
parent.Tick()

child.SetParent(parent)

var updater1 IUpdatable = parent
updater1.Update()

a1Parent := child.GetParent()
if a1Parent == parent {
	fmt.Println("==")
}
a1Parent.Tick()

updater2, ok := a1Parent.(IUpdatable)
if ok {
	updater2.Update()
}

}

func main() {
RunComponent1()
RunComponent2()
}

What is the question?

1 Like

ComponentB is IComponent
ComponentB is IUpdatable
ComponentB.AddChild(child)but child.GetParent() is not (IUpdatable, ComponentB )
but child.SetParent() and GetParent is IUpdatable and ComponentB

It seems you are attempting to use inheritance in Go,but Go does not have inheritance; only embedding.

When you write:

type ComponentB struct {
	Component
}

ComponentB does not “extend” Component. ComponentB wraps Component.

On this line:


	parent := new(ComponentB)
	parent.Name = "parent"
	parent.AddChild(child)	// <<<
	parent.Tick()

The implementation is this:

// Notice this ↓ is `Component`, not `ComponentB`
func (c *Component) AddChild(child IComponent) {
	child.SetParent(c)

	// other
}

So when you call parent.AddChild(child), it is syntactic sugar for parent.Component.AddChild(child) which then adds parent.Component as the parent of child; not parent.

The right solution depends on context. In your example, I don’t see what the purpose of AddChild is.
It seems reasonable to just call child.SetParent(parent) and get rid of AddChild. If in your actual code, AddChild does something more than call SetParent, could you show that code? If it depends on the implementation of the parent, then maybe you need to implement AddChild on the parents. If it is the same code for all component implementations, then make it a top-level function:

func AddChild(parent, child IComponent) {
    // Whatever common initialization you want
    child.SetParent(parent)
    // Maybe additional code here?
}

P.S.: It seems to me that you are attempting to write C# code in Go syntax, but they are two different languages and often cannot be translated line-for-line, similarly to C# and JavaScript or TypeScript, etc…

I recommend checking out A Tour of Go - Methods and Interfaces. Some of the beginning slides you can just page through, but I recommend reading about interfaces starting from slide #9 to see how they differ from C#.

c is ComponentB? but child.getParent is not ComponentB
p:=child.getParent().(*ComponentB)

embedding Can reduce code copy, does not inheritance, I understand that
but c is not ComponentB?why

now,I don’t use embedding

copy Component to ComponentB ,result is right

type ComponentB struct {
Name string
Parent IComponent
}

func (c *ComponentB) GetParent() IComponent {
return c.Parent
}

func (c *ComponentB) SetParent(parent IComponent) {
c.Parent = parent
}

func (c *ComponentB) AddChild(child IComponent) {
child.SetParent(c)

//other

}

so My question is embedding,
func (c *Component) AddChild(child IComponent)

c is Component,ComponentB has lost,No object-oriented programming language is like this

p:=c.(*ComponentB) crash
p:=c.(*IUpdatable) crash

c is only Component or IComponent

I personally think this is a compiler bug,go compiler should replace Component to ComponentB,because embedding to reduce code copy

This is not a compiler bug. Go is designed this way on purpose.

Some people say Go is not an object-oriented language. Personally, I consider it object-oriented, but it does not have inheritance. The C# equivalent to your Go code (minus the implementation of RunComponent2 is this:

C# code here
using System;

RunComponent1();
//RunComponent2();

public interface IComponent
{
	IComponent GetParent();
	void SetParent(IComponent parent);
	void Tick();
}

public interface IUpdatable
{
	void Update();
}

public class Component : IComponent
{
	public string Name;
	public IComponent Parent;

	public IComponent GetParent() => Parent;
	public void SetParent(IComponent parent) => this.Parent = parent;
	public void AddChild(IComponent child) => child.SetParent(this);
	public void Tick() => Console.WriteLine("base Tick");
}

public class ComponentA : IComponent
{
	public readonly Component Component = new Component();

	public string Name { get => Component.Name; set => Component.Name = value; }
	public IComponent Parent { get => Component.Parent; set => Component.Parent = value; }
	public IComponent GetParent() => Component.GetParent();
	public void SetParent(IComponent parent) => Component.SetParent(parent);
	public void AddChild(IComponent child) => Component.AddChild(child);
	public void Tick() => Component.Tick();
}

public class ComponentB : IComponent, IUpdatable
{
	public readonly Component Component = new Component();

	public string Name { get => Component.Name; set => Component.Name = value; }
	public IComponent Parent { get => Component.Parent; set => Component.Parent = value; }
	public IComponent GetParent() => Component.GetParent();
	public void SetParent(IComponent parent) => Component.SetParent(parent);
	public void AddChild(IComponent child) => Component.AddChild(child);

	public void Update() => Console.WriteLine("ComponentB Update");
	public void Tick()
	{
		Console.WriteLine("ComponentB Tick");
		Update();
	}
}

void RunComponent1()
{
	Console.WriteLine("#####################RunComponent1##################################");
	var child = new ComponentA();
	child.Name = "child";

	var parent = new ComponentB();
	parent.Name = "parent";
	
	parent.AddChild(child);
	parent.Tick();

	IUpdatable updater1 = parent;
	updater1.Update();

	var a1Parent = child.GetParent();
	if (a1Parent == parent) {
		Console.WriteLine("==");
	}
	a1Parent.Tick();

	if (a1Parent is IUpdatable updater2)
	{
		updater2.Update();
	}
}

/*
func RunComponent2() {
fmt.Println(“#####################RunComponent2##################################”)
child := new(ComponentA)
child.Name = “child”

parent := new(ComponentB)
parent.Name = "parent"
parent.Tick()

child.SetParent(parent)

var updater1 IUpdatable = parent
updater1.Update()

a1Parent := child.GetParent()
if a1Parent == parent {
	fmt.Println("==")
}
a1Parent.Tick()

updater2, ok := a1Parent.(IUpdatable)
if ok {
	updater2.Update()
}
}
*/

Notice that I wrote:

public class ComponentA
{
    public readonly Component Component = new Component();
}

And not

public class ComponentA : Component { }

Because Go has no inheritance.

Thank you for doing a lot of work,please See the following “c” code

#include <stdio.h>

//父结构体
struct BaseComponent
{
struct BaseComponent * parent
};

void add_child(struct BaseComponent * this,struct BaseComponent * child)
{
//add to map/list
child->parent=this;
}

struct BaseComponent * get_parent(struct BaseComponent * this)
{
return this->parent
}

struct ComponentParent
{
struct BaseComponent base_struct;
int a;
};

struct ComponentChild
{
struct BaseComponent base_struct;
int b;
};

int main(void)
{
struct ComponentParent parent;
struct ComponentChild child;

add_child(&parent,&child);

struct ComponentParent * child_parent=(struct ComponentParent *)get_parent(&child);

if(child_parent==&parent)
{
    printf("ok");
}

return 0;

}

I might write it like this in Go:

package main

import "fmt"

type Component interface {
	Parent() Component
	SetParent(parent Component)
}

func AddChild(parent, child Component) {
	//add to map/list
	child.SetParent(parent)
}

// 父结构体
type BaseComponent struct {
	parent Component
}

func (c *BaseComponent) Parent() Component          { return c.parent }
func (c *BaseComponent) SetParent(parent Component) { c.parent = parent }

type ComponentParent struct {
	BaseComponent
	a int
}

type ComponentChild struct {
	BaseComponent
	b int
}

func main() {
	var parent ComponentParent
	var child ComponentChild

	AddChild(&parent, &child)

	var childParent *ComponentParent = child.Parent().(*ComponentParent)

	if childParent == &parent {
		fmt.Println("ok")
	}

	var childParent2 = child.Parent()
	if childParent2 == &parent {
		fmt.Println("also ok")
	}
}

Good example.

I added this at the end:

	fmt.Printf("%v\n", child.parent == &parent)
	fmt.Printf("%v\n", child.BaseComponent.parent == &parent)

It demonstrates that ComponentChild “inherits” the “parent” field of BaseComponent, so it can be used like this: “child.parent”, which is equivalent to “child.BaseComponent.parent”.

I also added this, and it continued to work:

func (c *ComponentChild) SetParent(parent Component) {
	fmt.Printf("ComponentChild.SetParent()\n")
	c.BaseComponent.SetParent(parent)
}

ComponentParent and ComponentChild “inherit” the methods (Parent(), SetParent()), from BaseComponent. If ComponentParent defines its own SetParent() method,it will be used instead, when *ComponentParent is passed as a Component interface.

Note that Go does not have “virtual” or “abstract” methods, as defined in other languages, such as Java or C++. The equivalent in Go is to define and use an explicit interface (in this case Component). You can use a struct pointer where an interface type is expected, and you can cast an interface{} type back to its associated struct pointer, but you cannot cast a struct pointer to another struct pointer. Go separates polymorphism (interface types) from inheritance (embedding a struct in another struct). I find this a good thing.

I am bad at English,but I think about your code and advise at the past few days
I’ve been looking for solutions that I can accept:
first like “c” lang Change addChild(parent,child) to global function
second:Like you said,don’t call addchild,and call SetParent(parent ParentComponent)this like “Qt”

call child.SetParent (parent){
child.parent=parent
parent.addchild(child)
}

func (c *ComponentChild) SetParent(parent Component) {
fmt.Printf(“ComponentChild.SetParent()\n”)
c.BaseComponent.SetParent(parent)
parent.addchild(child)
}

This question makes me uneasy,thank you help me!!!