Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

One type is coerced into another, can a method to determine the type of the receiver?

Tags:

types

go

If types T1 and T2 are based on type T, and type T only comes into existence from a NewT1() or NewT2(), is there any way a function func (*T) WhoAmI() can know whether it "really" is a T1 or T2?

package main

import "fmt"
import "reflect"

type T struct{ s string }

func (v *T) WhoAmI() string {

    // pull type name with reflect
    fmt.Println(reflect.TypeOf(v).Elem().Name()) // always prints "T"!

    // todo: if I am actually T1
    return "T1"
    // todo: else if I am actually T2
    return "T2"
}

type T1 T

func NewT1(s string) T1 { return T1{s} }

type T2 T

func NewT2(s string) T2 { return T2{s} }

func main() {
    var t1 = T1{"xyz"}
    var t2 = T2{"pdq"}
    s1 := ((*T)(&t1)).WhoAmI() // would like to return "T1"
    s2 := ((*T)(&t2)).WhoAmI() // would like to return "T2"
    fmt.Println(s1, s2)
}

to speak technically:

once t1 type T1 is coerced into type T so func (*T) WhoAmI() can be called, does t1 completely lose the fact that its type is really T1? if not, how do we reclaim the knowledge from the perspective of a method receiving type T?

to speak generally:

in other words, if one type is based on another, if a variable of the derived type is coerced into the base type to run a method, can that method learn the real type of the receiver who called it?

like image 502
cc young Avatar asked Jun 26 '11 14:06

cc young


1 Answers

No, it's not possible. Creating a new type from an old one is not like creating a new class that inherits from a parent class in an class-based language. In your case T knows nothing about either T1 or T2 and if you're calling the WhoAmI method you have a receiver of type T by definition.

Your design might work better with an interface. Try something more like this:

type T interface {
    WhoAmI() string
}

type T1 struct {
    s string
}

func (t *T1) WhoAmI() string { return "T1" }

type T2 struct {
    s string
}

func (t *T2) WhoAmI() string { return "T2" }

Try it on the Go playground

T1 and T2 both implement the interface T, so they can be used as type T.

like image 82
Evan Shaw Avatar answered Sep 18 '22 01:09

Evan Shaw