Help with compile error, please

I’m fairly new to Golang. I am trying to implement what, in the C, language would be a tagged union. I found some example code on: Go and Algebraic Data Types - Eli Bendersky's website

I think I understand the example, and am trying to emulate it in my code. Here is a excerpt of my full program that gets an error that I don’t understand. It all seems okay to me.


package main

type Obj interface {
    isObj()
}

type Tspecial struct {
    subtype int
}

func (Tspecial) isObj() {}

func make_special(subtype int) *Obj {
	n := Tspecial{subtype}
	return &n
}

func main() {
    // dot := make_special(1)
}

It gets the following error with go version 1.19.1:

./test.go:15:9: cannot use &n (value of type *Tspecial) as type *Obj in return statement:
*Tspecial does not implement *Obj (type *Obj is pointer to interface, not interface)

I think I have things such that Tspecial implement Obj, so why wouldn’t the address of a Tspecial be a *Obj ?

In any case, can someone please tell me my error. I’m sure there’s a way to do what I’m trying to do.

package main

import "fmt"

type Obj interface {
	isObj()
}

type Tspecial struct {
	subtype int
}

func (ts *Tspecial) isObj() {}

func make_special(subtype int) Obj {
	n := Tspecial{subtype}
	return &n
}

func main() {
	dot := make_special(1)
	fmt.Println(dot)
}

Well, your suggestion compiles, bt I can’t understand why it does. It looks very wrong to me, because the function make_special says it returns an Obj, not a point to an Obj, and your code returns “&n”, the address of n, which should be a pointer to an Obj.

Can someone please explain, slowly, or point me to documentation, and help me understand this. I must be missing something fundamental.

Sure!

  • an interface value isn’t strictly a pointer or not a pointer, it’s just an interface

Please check this version first:

package main

import (
	"fmt"
	"reflect"
)

type Obj interface {
	isObj()
}

type Tspecial struct {
	subtype int
}

func (t Tspecial) isObj() {
	fmt.Println("Implementation of isObj in Tspecial")
}

func make_special(subtype int) Obj {
	n := Tspecial{subtype}
	n.isObj()
	fmt.Println(reflect.TypeOf(n))

	return n
}

func main() {
	dot := make_special(1)
	fmt.Println(dot)
	fmt.Println(reflect.TypeOf(dot))
}

It prints :
isObj:Tspecial implementation
TypeOf(n)= main.Tspecial
dot= {1}
TypeOf(dot)= main.Tspecial

Effectively Tspecial is considered as Obj because it implements all the required funcionality of that interface.
The problem is with pointers. One thing is a pointer to Tspecial and anoter thing is a pointer to Obj.

To return a *Obj from make_special ypou need to create a temp object of that type and cast “n” to that and then return his pointer.
It is something like:

func make_special(subtype int) *Obj {
	n := Tspecial{subtype}
	n.isObj()
	fmt.Println(reflect.TypeOf(n))
	o := Obj(n)
	return &o
}

HTH,
Yamil

Thank you, Yamil. I now know how to change my code slightly to make it work.

HOWEVER, can someone explain to me why the example from Gonzalo works. This one here:

package main

import "fmt"

type Obj interface {
	isObj()
}

type Tspecial struct {
	subtype int
}

func (ts *Tspecial) isObj() {}

func make_special(subtype int) Obj {
	n := Tspecial{subtype}
	return &n
}

func main() {
	dot := make_special(1)
	fmt.Println(dot)
}

The make_special function says it returns an Obj, not a pointer to an Obj, yet the function returns “&n”, a pointer to a Tspecial (which is an Obj). WHY is that not an error? And then, back main, the Println(dot) says that dot is “&(1)”, which is a pointer to a Tspecial. That is, make_special says it returns an Obj, but it apparently returns a *Obj.

The difference is pointer to a structure and pointer to an interface.
Please check this:

func writeObj(o Obj) {
	fmt.Printf("[%T] %+v\n", o, o)
}

func main() {
	a := Tspecial{1}
	var b *Tspecial = &Tspecial{2}

	writeObj(a)
	writeObj(b)
}

WriteObj can receive a struct and a pointer to that struct using an interface but not a pointer to an interface.