The reason is that if you could define methods on other packages' types, you could modify the behavior of other packages. This is because the method set of a given type can have an effect on how values of that type are used.
Consider, for example, the fmt.Println
function. When you pass an argument to fmt.Println
, it will print a string representation of that value based on a set of rules. One of those rules is that if the type of the value has a String() string
method (that is, it implements the fmt.Stringer
interface), then that method will be called in order to obtain the string representation of the value.
Thus, imagine that we have a package, foo
, and that package has a type, FooInt
, defined as follows:
type FooInt int
Now imagine that this package also has a function, PrintFooInt
:
func PrintFooInt(f FooInt) { fmt.Println(f) }
This will print the integer value of f
. But let's say that you (in a different package, say main
) were able to add methods to FooInt
. Then you could do this:
func (f FooInt) String() string { return "foobar!" }
This would actually change the behavior of foo.PrintFooInt
, which shouldn't be possible from outside the package.