14

When I define a custom type, it seems that the type of the underlying type makes a difference about whether I can pass it to a function as is or I need to convert it.

Question is: Why does RuneFunc and StringMap work, but not Integer?

https://play.golang.org/p/buKNkrg5y-

package main


type RuneFunc func(rune) rune
type Integer int
type StringMap map[string]string

func main() {
    //m := make(StringMap)
    //mf(m)


    var i Integer = 5
    nf(i)


    //var f func(rune) rune
    //ff(f) 

}

func mf(i map[string]string) {

}
func ff(i func(rune)rune) {

}
func nf(i int) {

}

Here, when I run this function called nf with Integer it complains although int is the underlying type. But when I call mf or ff they run successfully.

icza
  • 389,944
  • 63
  • 907
  • 827
HorusCoding
  • 675
  • 1
  • 6
  • 13

2 Answers2

22

Integer and int

int and your new type Integer are 2 different, distinct types. Where Integer is expected, you have to pass a value of type Integer.

If you have an Integer value, you may use a simple type conversion to make it a value of type int, because the underlying type of Integer is int:

var i Integer = 5
nf(int(i))

What may be confusing and interesting at the same time is that you are allowed to pass an untyped constant without conversion:

nf(5)

Try these on the Go Playground.

The reason for this is in the Spec: Assignability:

A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:

[...]

  • x is an untyped constant representable by a value of type T.

5 is an untyped constant which is representable by a value of type int because the untyped constant 5 has a default type int, so it is representable by a value of type Integer (which has the same default type).

If you check the other assignability rules (not included in above quotation), none of them match the case where you attempt to pass a value of Integer for the parameter of type int, so that's not allowed.

See related question: Golang: Creating a Constant Type and Restricting the Type's Values

RuneFunc and func(rune) rune

The difference between this case and the previous one (Integer and int) is that int is a named type and func(rune) rune is not.

And there's an assignability rule which allows this:

So in this case:

var f RuneFunc
ff(f)

f is a named type, but the parameter type of ff() is func(rune) rune which is unnamed, so the assignment is allowed.

Community
  • 1
  • 1
icza
  • 389,944
  • 63
  • 907
  • 827
  • Thank you for your time, the question is "Why does RuneFunc and StringMap work, but not Integer?" I've updated the main post, sorry If I didnt make my self clear. – HorusCoding Jan 06 '17 at 08:37
  • 3
    Interesting! I never took note of that rule or what it really meant before. – hobbs Jan 06 '17 at 08:40
1

Go has a strict type system. Just because your type is merely an alias for int doesn't mean you can interchange the two freely, you'll still have to do a type conversion. Below is a working version of your main, here's the code on play ground: https://play.golang.org/p/BDTXnnG9Lg

Jorj
  • 1,291
  • 1
  • 11
  • 32
  • 1
    But why it doesn't need type conversion for map[string]string or func(rune)rune? That is the question – HorusCoding Jan 06 '17 at 08:30
  • Upvoted like the accepted very thoughtful answer of @icza, as I also did not get the extended focus of the question right at first and before clarification and because I like your code provision in the go playground combined with the terse explanation of the Integer vs. int difference. – Dilettant Jan 06 '17 at 11:35