In the program below, can someone explain why the compiler treats Int and int as non-interchangeable but
map[interface{}]interface{} and Map as interchangeable?
Note, when lines 42 and 43 are uncommented, this is what the compiler gives:
test2.go:42: cannot use i2 (type Int) as type int in function argument
test2.go:43: cannot use i (type int) as type Int in function argument
I am using the latest 8g compiler.
Thanks,
John
-----
//
package main
import (
"fmt"
"reflect"
)
type Int int
type Map map[interface{}]interface{}
func Printint(i int) {
fmt.Printf("int (%s) (%v)\n", i, i)
}
func PrintInt(i Int) {
fmt.Printf("Int (%s) (%v)\n", i, i)
}
func Printmap(m map[interface{}]interface{}) {
fmt.Printf("map (%v)\n", reflect.Typeof(m))
for k, v := range m {
fmt.Printf("k (%v) v (%v)\n", k, v)
}
}
func PrintMap(m Map) {
fmt.Printf("Map (%v)\n", reflect.Typeof(m))
for k, v := range m {
fmt.Printf("k (%v) v (%v)\n", k, v)
}
}
func main() {
i := 1
i2 := Int(2)
Printint(i)
PrintInt(i2)
//Printint(i2) // line 42: won't compile
//PrintInt(i) // line 43: won't compile
fmt.Printf("-----\n")
m := map[interface{}]interface{} {
"x": 1,
}
m2 := Map {
"x": 2,
}
fmt.Printf("m (%v)\n", reflect.Typeof(m))
fmt.Printf("m2 (%v)\n", reflect.Typeof(m2))
Printmap(m)
PrintMap(m2)
Printmap(m2)
PrintMap(m)
}
Here's a much simpler example showing the effect; since Pint and *int
are equivalent but only one is named. This compiles without incident.
package main
func main() {
type Pint *int
var p *int
var P Pint
p = P
_ = p
}
-rob
Pint and Xint are named types with *int as the underlying type (right?). Now Xint
and Pint will be treated as *int and can be passed to "func x(*int)", but Xint will
_not_ be treated as Pint, and cannot be passed to "func y(Pint)", is that correct?
If this is true, can you give an explanation (or point me to the doc) on why this is
so (I suspect my misunderstanding is b/c of coming from OO).
Thanks,
John
The reasoning goes like this: If you take the trouble to name Pint and
Xint, it's because you want them to be distinct. (This isn't C, where
a typedef is just an alias.) But sometimes it makes sense to speak of
the structure as all you care about; consider things like the indexing
functions in the bytes package. So we allow assignment in those
cases.
The motivating example in our thinking was something like type Point
struct { X, Y float }. Another named type with the same fields
probably is a different idea or it would share the declaration; they
shouldn't be interchangeable. Another way to say it is that if they
don't have the same methods (even potentially), they shouldn't be
assignable. On the other hand a generic struct { X, Y int } is
talking just about the structure, not its interpretation, so it makes
sense to allow assignment between that type and Point.
Also, although I cannot reconstruct the history, the current rules
were arrived at largely through experience coupled with a desire for a
simple specification. They aren't arbitrary.
-rob
So, other than explaining how types work, is there much of a use case
for the T2 in the examples in the spec?
type T1 string
type T2 T1
It would seem that "type T2 T1" actually hides (e.g., if it was in a
separate file) the fact that the underlying type of T2 is string and could
only be used with functions dealing with string (and those of T2).
Thanks again,
John
string is another named type so you couldn't pass a T1 where a string
is expected. The use in the spec is for illustration purposes. The
purpose of such a declaration could be to ensure the two types T1 and
T2 are represented the same even if that representation changes, so
they will always be conversion compatible. This makes more sense in
the more complex case of a struct type, where it's not only more
likely for the definition to change, but this type of transitory
declaration reduces code duplication and makes the relationship clear,
and it may not even be possible to declare the two types independently
of each other and still have them be conversion compatible (if the
types are declared in separate packages and have private fields).
John