7

I'm wondering why the functions are not working with types of the same kind ? See the following pseudo functions.

Playground: http://play.golang.org/p/ZG1jU8H2ZJ

package main

type typex struct {
    email string
    id    string
}

type typey struct {
    email string
    id    string
}

func useType(t *typex) {
    // do something
}

func main() {
    x := &typex{
        id: "somethng",
    }
    useType(x) // works

    y := &typey{
        id: "something",
    }
    useType(y) // doesn't work ??
}
siritinga
  • 4,063
  • 25
  • 38
user3721073
  • 253
  • 2
  • 4
  • 7

2 Answers2

8

Because they are separate types.

What you're after is an interface that Go can use to guarantee that the types contain the same signatures. Interfaces contain methods that the compiler can check against the types being passed in.

Here is a working sample: http://play.golang.org/p/IsMHkiedml

Go won't magically infer the type based on how you call it. It will only do this when it can guarantee that the argument at the call site matches that of the input interface.

Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138
  • An interface is not necessary here since the type is easily convertible, as stated in the [other answer](http://stackoverflow.com/a/24384133/1643939). Note that conversions are not unchecked casts but compile-time checked conversions that do not compromise memory safety. Interfaces are overkill in this case. See also [this question](http://stackoverflow.com/q/24613271/1643939). – nemo Jul 07 '14 at 15:45
  • 1
    @nemo I understand this now (I've had a couple of weeks to do some more thorough reading on this). Thanks for the links and explanation. I do like that it is compile-time checked - that really makes me feel better about the below answer :) – Simon Whitehead Jul 07 '14 at 22:17
8

As to the why - Y is not X so why would it work?

You can easily overcome this, if they really are identical, by casting typey into typex:

useType((*typex)(y))

However, if they are identical, why have 2 types?

Not_a_Golfer
  • 47,012
  • 14
  • 126
  • 92
  • Does that really work? That's horrible :/ +1 anyway. – Simon Whitehead Jun 24 '14 at 10:22
  • Horrible might be a strong word. What I mean is that casting it like that sort of goes against what I've seen from Go so far. – Simon Whitehead Jun 24 '14 at 10:25
  • @SimonWhitehead Agreed. I put this here however because it surprised me too that it can be done. – Not_a_Golfer Jun 24 '14 at 10:27
  • 5
    @SimonWhitehead, this works because typex and typey have the same underlying type, so, it is possible to do a conversion. In fact, what Not_a_Golfer is doing here is equal to defining: `type typex struct {email, id string}; type typey typex;` See http://play.golang.org/p/I5yayfmRYJ – rvignacio Jun 24 '14 at 13:00
  • @rvignacio it's not what I did but what the person who asked this did :) – Not_a_Golfer Jun 24 '14 at 15:14
  • @Not_a_Golfer, yes, sorry, I said it because your code works... since the OP's code does not compile =P – rvignacio Jun 24 '14 at 16:17
  • @rvignacio "Same underlying type" - can you provide a reference for information regarding that? Does the compiler combine types that are identical? – Simon Whitehead Jun 24 '14 at 21:05
  • @SimonWhitehead, this is explained in [The Laws of Reflection](http://blog.golang.org/laws-of-reflection), Go is statically typed, so `typex` and `typey` are two different static types... but the underlying type is the same literal struct. It's like defining `type X int` and `type Y int`, you will need to make a conversion between types, but under the covers... they are both the same (that's why you can convert one type to another). I have to read about the compiler and reflection to know how it really works in these cases, sorry but I'm not able to give you a more detailed answer right now. – rvignacio Jun 25 '14 at 12:04
  • 1
    @rvignacio Thanks for the explanation. I've had a couple of weeks to do some reading and it makes sense now. This concept felt foreign to me: my C/C++ background tells me that this is an unchecked cast.. but my .NET background says this _should_ be checked. Turns out, it is. I retract my "horrible" statement :) – Simon Whitehead Jul 07 '14 at 22:19