Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I type alias functions and use them without casting?

Tags:

types

casting

go

In Go, if you define a new type e.g.:

type MyInt int 

You can't then pass a MyInt to a function expecting an int, or vice versa:

func test(i MyInt) {     //do something with i }  func main() {     anInt := 0     test(anInt) //doesn't work, int is not of type MyInt } 

Fine. But why is it then that the same does not apply to functions? e.g.:

type MyFunc func(i int) func (m MyFunc) Run(i int) {     m(i) }  func run(f MyFunc, i int) {     f.Run(i) }  func main() {     var newfunc func(int) //explicit declaration     newfunc = func(i int) {         fmt.Println(i)     }     run(newfunc, 10) //works just fine, even though types seem to differ } 

Now, I'm not complaining because it saves me having to explicitly cast newfunc to type MyFunc, as I would have to do in the first example; it just seems inconsistent. I'm sure there is a good reason for it; can anyone enlighten me?

The reason I ask is mainly because I would like to shorten some of my rather long function types in this way, but I want to make sure it's expected and acceptable to do this :)

like image 431
jsdw Avatar asked Oct 12 '13 13:10

jsdw


People also ask

When to use type alias?

Type aliases provide alternative names for existing types. If the type name is too long you can introduce a different shorter name and use the new one instead.

What is type aliases in kotlin?

In a project, we might declare variables of the same datatype multiple times like declaring a variable of Api response class type in Android or maybe using the same function again and again which might not make your code readable.

What is type Golang?

Type is the base interface for all data types in Go. This means that all other data types (such as int , float , or string ) implement the Type interface. Type is defined in the reflect header.


1 Answers

Turns out, this is a misunderstanding that I had about how Go dealt with types, which can be resolved by reading the relevant part of the spec:

http://golang.org/ref/spec#Type_identity

The relevant distinction that I was unaware of was that of named and unnamed types.

Named types are types with a name, such as int, int64, float, string, bool. In addition, any type you create using 'type' is a named type.

Unnamed types are those such as []string, map[string]string, [4]int. They have no name, simply a description corresponding to how they are to be structured.

If you compare two named types, the names must match in order for them to be interchangeable. If you compare a named and an unnamed type, then as long as the underlying representation matches, you're good to go!

e.g. given the following types:

type MyInt int type MyMap map[int]int type MySlice []int type MyFunc func(int) 

the following is invalid:

var i int = 2 var i2 MyInt = 4 i = i2 //both named (int and MyInt) and names don't match, so invalid 

the following is fine:

is := make([]int) m := make(map[int]int) f := func(i int){}  //OK: comparing named and unnamed type, and underlying representation //is the same: func doSlice(input MySlice){...} doSlice(is)  func doMap(input MyMap){...} doMap(m)  func doFunc(input MyFunc){...} doFunc(f) 

I'm a bit gutted I didn't know that sooner, so I hope that clarifies the type lark a little for someone else! And means much less casting than I at first thought :)

like image 140
jsdw Avatar answered Oct 11 '22 23:10

jsdw