type aliasing

10,893 views
Skip to first unread message

serega

unread,
Nov 28, 2009, 10:42:39 AM11/28/09
to golang-nuts
Consider the following code:
package main

import (
"fmt";
)

type MyType int;

func printInt(i int) {
fmt.Printf("%d\n", i);
}

func main() {
var i int = 1;
i++;
printInt(i);

var my_type MyType = 1;
my_type++;
printInt(my_type);// error: cannot use my_type (type MyType) as
type int in function argument
}

The compiler allows to use increment operator to MyType, but why
doesn't it allow to use MyType as an argument in int function?

Sergey.

gorgo...@online.de

unread,
Nov 28, 2009, 2:13:13 PM11/28/09
to golang-nuts
in go, all types are distinct. one can't use types derived from
integers instead of integers. if you want to use both types
interchangeably, printInt needs to ask for an *interface* to which
both types are *compatible*. in this case, this is the *empty
interface*.

please see the docs for types and interfaces.

--
GorgonZola <gorgo...@online.de>

Crwth

unread,
Nov 28, 2009, 3:14:14 PM11/28/09
to gorgo...@online.de, golang-nuts
In a sense, I think Sergey's question should have been the other way around:  since it doesn't allow him to use my_type as a type int in a function argument, why does it allow the use of the increment operator?  The first behaviour is the most noted (this is probably my biggest complaint(?)/hurdle(?) with Go -- the amazing number of typecasts in my code), and the fact that the operator "burrows down" to find that it can indeed be used on this variable is perhaps a surprising (yet welcome) feature.

--
  Crwth

gorgo...@online.de

unread,
Nov 28, 2009, 4:11:18 PM11/28/09
to golang-nuts
On Sat, 28 Nov 2009 13:14:14 -0700
Crwth <cry...@gmail.com> wrote:

> In a sense, I think Sergey's question should have been the other way around:
> since it doesn't allow him to use my_type as a type int in a function
> argument, why does it allow the use of the increment operator? The first
> behaviour is the most noted (this is probably my biggest
> complaint(?)/hurdle(?) with Go -- the amazing number of typecasts in my
> code), and the fact that the operator "burrows down" to find that it can
> indeed be used on this variable is perhaps a surprising (yet welcome)
> feature.
>
> --
> Crwth
>

funnily, the principle of go is fully clear to me but how to make use
of it is still a riddle to me!? the devil is in the detail, people say.
go comes along like an imperative language but enforces the bottom-up
approach. one can see this in the (yet) centralized, and strongly
inheriting, package tree but also in how interfaces are designed.
putting a program on top of this and trying to build bridges top down is
quite against how go is designed. this is why the go core developers
have the full overview while the application programmers (outsiders)
only see a surface that behaves strange if not rejects own code. to be
good in go, one possibly has to grow up from the very below of it.

if one sees things bottom up, much becomes more clear. MyType is like a
subclass of type int and thus allowed to extend the type int. in other
words: it is allowed to differ! this is why it can't be held for being
the same. however, because it is like a subclass of int, it provides
same functionality. so easy it is. this also explains why you need so
many casts. you think in types and create lots of differences by that.
you should think in interfaces and grow your code bottom up around
them. let the interfaces build the skeleton and keep the special types
most isolated.

however, i didn't say anything! can't even create channel chains
successfully at the moment ;)


--
GorgonZola <gorgo...@online.de>

Brian Slesinsky

unread,
Nov 28, 2009, 7:51:00 PM11/28/09
to golang-nuts
Yes, if you want that, you should write:

printInt(int(my_type));

The idea is to avoid accidentally mixing MyType with a bare int.

ziyu_huang

unread,
Nov 28, 2009, 8:45:28 PM11/28/09
to golang-nuts
type in Go is not typedef in C. It's acually define a new type. Though
Go compilter think they are compatible, so you can cast it, like "int
(my_type)"

i3dmaster

unread,
Nov 28, 2009, 11:43:06 PM11/28/09
to golang-nuts
I have feeling that in Go, if you'd like to have your code to be
generic, use interface parameters instead of concrete types and then
it will behave like duck typing.

type Reader interface {
Read();
}

func ReadMe(reader Reader) {
reader.Read();
}

Now, you can feed this function with anything that implements Reader
interface. It does not care whatever concrete types anymore...

But how this idiom can be applied to primitive types? In huang's
example,

what generic interface should he put so that printInt can take all
types inherited from int?

func printInt(i IntInterface) {
fmt.Println("%d\n", i);
}

and then you can do printInt(10) and printInt(my_type)?

Brian Slesinsky

unread,
Nov 29, 2009, 12:37:38 AM11/29/09
to golang-nuts
To get that you would have to define your own interface and new types
based on each kind of integer that implements the interface. Could be
done but it would be slow and doesn't seem worthwhile.

For the specific problem of printing, you implement the fmt.Stringer
interface and it will work with the printing functions in fmt.

- Brian

Russ Cox

unread,
Nov 29, 2009, 1:06:15 PM11/29/09
to Crwth, gorgo...@online.de, golang-nuts
On Sat, Nov 28, 2009 at 12:14, Crwth <cry...@gmail.com> wrote:
> In a sense, I think Sergey's question should have been the other way around:
>  since it doesn't allow him to use my_type as a type int in a function
> argument, why does it allow the use of the increment operator?

Because the increment operator applies to any arithmetic
type, not just "int". Int is one instance of an arithmetic type
and also one instance of an integer type, but it need not be
the only one.

Russ

i3dmaster

unread,
Nov 29, 2009, 2:34:00 PM11/29/09
to golang-nuts


On Nov 28, 9:37 pm, Brian Slesinsky <bslesin...@gmail.com> wrote:
> To get that you would have to define your own interface and new types
> based on each kind of integer that implements the interface. Could be
> done but it would be slow and doesn't seem worthwhile.
>
> For the specific problem of printing, you implement the fmt.Stringer
> interface and it will work with the printing functions in fmt.
That's right, but it does not solve the generics question. For a given
function, how to make it generic for custom types and primitives? Even
if you implement String() method, you still can't pass a my_type
object to the printInt function. The problem is at the parameter type.
I think it will require the language to support autoboxing, but then
it becomes a trade-off thing again. Speed vs. runtime overhead...

atomly

unread,
Nov 29, 2009, 2:50:51 PM11/29/09
to i3dmaster, golang-nuts
On Sun, Nov 29, 2009 at 2:34 PM, i3dmaster <i3dm...@gmail.com> wrote:
> That's right, but it does not solve the generics question. For a given
> function, how to make it generic for custom types and primitives? Even
> if you implement String() method, you still can't pass a my_type
> object to the printInt function. The problem is at the parameter type.
> I think it will require the language to support autoboxing, but then
> it becomes a trade-off thing again. Speed vs. runtime overhead...

Why not have a print function that takes a one-method interface which
returns data in the desired type? (c.f. Reader)

--
:: atomly ::

[ ato...@atomly.com : www.atomly.com : http://blog.atomly.com/ ...
[ atomiq records : new york city : +1.917.442.9450 ...
[ e-mail atomly-new...@atomly.com for atomly info and updates ...

gorgo...@online.de

unread,
Nov 29, 2009, 3:18:59 PM11/29/09
to golan...@googlegroups.com
i already answered this in this thread. your printInt function is
explicitly targeting at the int type. types are distinct, which means
that int and MyType are not equal. you must define a function that asks
for a generic *interface type* - a contract - to which both int and
MyType are *compatible*. by default, all types support the *empty
interface*, written "interface{}". this can always be used. try
the code below and you see that it works:

package main

import "fmt"

type MyInt int


func print (i interface{}) {
fmt.Printf("%d", i);
}

func main () {

var i MyInt;
i = 5;
print(i);

}

however, because you now could also pass strings, arrays and all other
types, it is always better to not try to base your code on generic
types but rather write code based on higher-order interface types and
types with methods that can put in some more control and casting where
necessary. so, printInt is not the best choice in your case anyway.

try this and you see that it works too:

package main

import "fmt"

type MyInt int


func print (i interface{}) {
fmt.Printf("%d\n", i);
fmt.Printf("%s\n", i);
}

func main () {

var i MyInt;
i = 5;
print(i);

var s string;
s = "hello";
print(s);

}

strange but true!

---

GorgonZola <gorgo...@online.de>

atomly

unread,
Nov 29, 2009, 3:33:58 PM11/29/09
to gorgo...@online.de, golan...@googlegroups.com
On Sun, Nov 29, 2009 at 3:18 PM, <gorgo...@online.de> wrote:
> On Sun, 29 Nov 2009 14:50:51 -0500
> atomly <ato...@atomly.com> wrote:
>> Why not have a print function that takes a one-method interface which
>> returns data in the desired type?  (c.f. Reader)
>
> i already answered this in this thread. your printInt function is
> explicitly targeting at the int type. types are distinct, which means
> that int and MyType are not equal. you must define a function that asks
> for a generic *interface type* - a contract - to which both int and
> MyType are *compatible*. by default, all types support the *empty
> interface*, written "interface{}". this can always be used. try
> the code below and you see that it works:

... snipped ...

Exactly, which is why I suggested something safer and more explicit.

Write your print function to take an argument of a given interface.
Define that interface to have only one method, which returns the data
in the format you want (in this case, apparently, int). Now anything
you want to print just has to have that method and it'll work, plus
it's safe at compile and run time.

Something incredibly simple like this:

type MyInt interface {
GetInt() (n int);
}

func print (i MyInt) {
fmt.Printf("%d", i.GetInt());

Crwth

unread,
Nov 29, 2009, 4:16:14 PM11/29/09
to r...@golang.org, gorgo...@online.de, golang-nuts
So in a sense, making a new type based on an arithmetic type passes the arithmeticness along.  Clear enough.  Cheers.

--
  Crwth

i3dmaster

unread,
Nov 29, 2009, 5:45:42 PM11/29/09
to golang-nuts
I don't see how this would help to solve the original question though.
You solution only helps when subtypes all implement the MyInt
interface. It still fails when passing just a primitive int type.

The original question is if one subtypes from a primitive type, how to
write functions to support both types, explicitly, all custom types
from the derived type and the primitive type.

type MyInt int
type MyAnotherInt MyInt
...

print(a_generic_enough_type) so that passing int, MyInt, MyAnotherInt,
etc... all works. I think currently there isn't a way to do this. Go
does not support type hierarchy. int, MyInt, etc.. are explicit
different types. GorgonZola provided a "far" generic solution is to
take an interface{} type, but that pretty much tells the compiler to
just avoid type checking, which he had already pointed out being too
ricky...

I think unless the language implements autoboxing, there will be no
way to have a "high-enough" interface that is "compatible" with
primitives and custom types derived from them. Is that the reason Java
finally introduced autoboxing?


On Nov 29, 12:33 pm, atomly <ato...@atomly.com> wrote:
> [ e-mail atomly-news-subscr...@atomly.com for atomly info and updates ...

Brian Slesinsky

unread,
Nov 29, 2009, 7:07:15 PM11/29/09
to golang-nuts

On Nov 29, 2:45 pm, i3dmaster <i3dmas...@gmail.com> wrote:
> I don't see how this would help to solve the original question though.
> You solution only helps when subtypes all implement the MyInt
> interface. It still fails when passing just a primitive int type.

I believe the point is that the original question doesn't necessarily
need to be solved because you can easily cast any integer type to your
own integer type that implements your interface.

Q. How can I write a function that takes any integer type?
A. Don't do that. Instead, define a new interface and implement it for
each integer type you care about.

If we have:

type AnyInt interface { ... something ... };

type MyInt int;
// methods so that MyInt implements AnyInt

type YourInt int;

var m MyInt;
var i int;
var y YourInt;

func printInt(AnyInt a) { ... }

I believe we can write:

printInt(m);
printInt(MyInt(i));
printInt(MyInt(int(y)));

It might be nice if there some way the author of printInt() could get
rid of some boilerplate type conversion for the callers, but that's
complicated and there's a solution that works today.
(If the author of YourInt wants to be nice they could implement AnyInt
to make that last call easier.)

Then again, it might be more practical to take an int64. Or not. It's
hard to tell given a toy example.

I think once people start writing libraries that should work together,
they will have to decide on some of the interfaces that don't exist in
the standard packages, and then it would be useful to document what
those interfaces should be.

- Brian

SnakE

unread,
Nov 29, 2009, 7:31:45 PM11/29/09
to i3dmaster, golang-nuts
2009/11/30 i3dmaster <i3dm...@gmail.com>

I think unless the language implements autoboxing, there will be no
way to have a "high-enough" interface that is "compatible" with
primitives and custom types derived from them. Is that the reason Java
finally introduced autoboxing?

Go does enough magic under the hood already.  I think it should be easy to add a magical interface, Arithmetic, which would match any type supporting arithmetic operators.  Though this will be very close to implicit casts.

Yongjian Xu

unread,
Nov 29, 2009, 8:17:16 PM11/29/09
to Brian Slesinsky, golang-nuts
On Sun, Nov 29, 2009 at 4:07 PM, Brian Slesinsky <bsles...@gmail.com> wrote:

On Nov 29, 2:45 pm, i3dmaster <i3dmas...@gmail.com> wrote:
> I don't see how this would help to solve the original question though.
> You solution only helps when subtypes all implement the MyInt
> interface. It still fails when passing just a primitive int type.

I believe the point is that the original question doesn't necessarily
need to be solved because you can easily cast any integer type to your
own integer type that implements your interface.
Well yes, and I guess that's also the usage of autoboxing, isn't it? The compiler does it for you instead of you "programmer" to explicitly do it. 

Q. How can I write a function that takes any integer type?
A. Don't do that. Instead, define a new interface and implement it for
each integer type you care about.
I am not sure if I would agree that. At least for any "int" type and subtypes, e.g. the MyInt and YourInt are all subtypes of int, printlnt(i int) should work with all these types. Same as other int types, such int32, int64, any subtypes of those should work with corresponding functions that takes int32, and int64. Languages claimed pure OO has no primitives, they are all objects subtyped from a generic type, say object. If in Go's case, it would be these int, int32, float, etc... be a subtype of interface{}, or say 'type Integer interface{}' for all int types, then you can write function to accept 'Integer' which will be compatible with all 'int' types. OO Languages do have primitives pretty much adopted autoboxing. Java finally decided to go that route after C#. There got to be a reason for that I think. I feel that Go is in the stage like Java before it introduced autoboxing for this particular matter. I guess only practice will tell whether this will be a benefit for Go.

serega

unread,
Nov 29, 2009, 9:48:26 PM11/29/09
to golang-nuts
My original question is not necessarily about printing integers. I
hate in Java writing Map<Integer,Map<Integer,Integer>> m = new
HashMap<Integer,Map<Integer,Integer>>.
In C/C++ it is possible to avoid that by using typedefs.

I was surprised that the following works

type MapOfMaps map[int] map[int] int;

func printMapOfMaps(m map[int] map[int] int) {
fmt.Printf("%s\n", m);
}

func main() {
var mm MapOfMaps = make(map[int] map[int] int);
mm[1] = make(map[int] int);
printMapOfMaps(mm);

var mm2 map[int] map[int] int = mm;
printMapOfMaps(mm2);
}


, but it does not work for integers.
So, MapOfMaps is compatible with map[int] map[int] int, but MyInt is
not compatible with int.

serega

unread,
Nov 29, 2009, 10:06:09 PM11/29/09
to golang-nuts
Here is simpler example which does not compile

type (
T2 struct { a, b int };
T3 struct { a, b int };
)


func main() {
var t2 T2 = T2{1, 2};
var t3 T3 = T3{1, 2};

t2 = t3; //cannot use t3 (type T3) as type T2

fmt.Printf("%s, %s", t2, t3);
}

Based on the language specs http://golang.org/doc/go_spec.html#Types
T2 and T3 are compatible, and should be assignable to each other.

Russ Cox

unread,
Nov 29, 2009, 10:10:25 PM11/29/09
to serega, golang-nuts
> So, MapOfMaps is compatible with map[int] map[int] int, but MyInt is
> not compatible with int.

Yes.

Type compatibility is less stringent than type identity:
a named and an unnamed type are compatible if the
respective type literals are compatible.
http://golang.org/doc/go_spec.html#Type_identity_and_compatibility

"int" and "MyInt" are both named types, so this sentence
doesn't apply in that case.

Why is it like this? Because much of the time type names
for composite types like

type MapOfMaps map[int] map[int] int

are serving only as shorthands, not trying to introduce a
distinct type. But if a type has two different names
that is clearly not a shorthand and shouldn't be converted
silently (in particular, it could change the meaning of
methods from one to the other). The case that comes
up in practice is giving names to functions, like

type Op func(int, int) int

This is obviously a kludge: there should be two different ways
to introduce names, one that is just a shorthand and
one that creates a distinct (not compatible) type.
But we had a very hard time coming up with a shorthand
mechanism that we liked. The syntax is only a small
part: the big semantic problem is that once you introduce
these shorthands (let's call them typedefs), you can now
have two spellings that mean the same type (are identical types,
in the language of the spec). When you print a compiler error
or a type diagnostic or any of the other places that a type
is spelled out, which spelling do you use? How do you decide?
This seems like a tiny thing but C (and especially C++)
compilers struggle mightily with it [1], and they only have to
print types in error messages (there are no runtime concerns).

Go avoids all that complexity by not having typedef. The
named + unnamed compatibility rule is a small nod to
compensate for that lack in the situations where typedef
is most missed. In practice, it seems to be a good trade,
but it's certainly not the most principled part of the language.

> Based on the language specs http://golang.org/doc/go_spec.html#Types
> T2 and T3 are compatible, and should be assignable to each other.

Two types T2 and T3 can never be compatible: they are
both named, and the names are different (see definition
above).

Russ

[1] g++ x.cc

#include <string>
#include <vector>
using namespace std;
int f(vector<string>* v);
int g(vector<string> v) { f(g); }

j-g-faustus

unread,
Nov 29, 2009, 11:05:05 PM11/29/09
to golang-nuts
> "int" and "MyInt" are both named types, so this sentence
> doesn't apply in that case.

You are saying that 'int' is a named type while 'map[int]int' is not?

I thought all the primitive types - bool, string, int etc. - were
unnamed, and named types were those renamed by the programmer rather
than supplied by the language? I was apparently wrong.

So let me try a second guess:
* all primitive types are named types
* all types named by the developer are named types (obviously)
* the term "unnamed type" is reserved for anonymous composite types:
interfaces, structs, function types, arrays, slices, maps and
channels.

Is this correct?

i3dmaster

unread,
Dec 4, 2009, 3:01:52 AM12/4/09
to golang-nuts
I am a little vague on that "unnamed" type too. My understanding is
that a "unnamed" type is a literal that will denote to some type in
compile time, say if I pass
f(10), then that 10 refers to a unnamed type. The compiler would give
it a int type and then see if the function takes ints... But if you
say var a int = 10, f(a), then that's a named type. Am I getting this
right??

Russ Cox

unread,
Dec 4, 2009, 3:19:57 AM12/4/09
to j-g-faustus, golang-nuts
> You are saying that 'int' is a named type while 'map[int]int' is not?
>
> I thought all the primitive types - bool, string, int etc. - were
> unnamed, and named types were those renamed by the programmer rather
> than supplied by the language? I was apparently wrong.
>
> So let me try a second guess:
> * all primitive types are named types
> * all types named by the developer are named types (obviously)
> * the term "unnamed type" is reserved for anonymous composite types:
> interfaces, structs, function types, arrays, slices, maps and
> channels.
>
> Is this correct?

Yes, but there is an easier explanation:
a named type is one identified by a name.
That is, if the type is spelled with just a single
identifier, it is a named type. (And "int" is an
identifier no different from "x", except that it
is predeclared.)

Russ

Ian Lance Taylor

unread,
Dec 4, 2009, 9:50:46 AM12/4/09
to i3dmaster, golang-nuts
i3dmaster <i3dm...@gmail.com> writes:

> I am a little vague on that "unnamed" type too. My understanding is
> that a "unnamed" type is a literal that will denote to some type in
> compile time, say if I pass
> f(10), then that 10 refers to a unnamed type. The compiler would give
> it a int type and then see if the function takes ints... But if you
> say var a int = 10, f(a), then that's a named type. Am I getting this
> right??

Not really. An unnamed type is a type like "[]byte": it doesn't have
a name. You can't refer to that type again, you can just write down
another identical type "[]byte". Types like "int", "string", or
anything named by a type declaration have names.

A constant like 10 is untyped: it doesn't have a type at all.
When the constant is used outside of a constant expression, it will be
given a type.

Ian

Helmar

unread,
Dec 4, 2009, 10:07:51 AM12/4/09
to golang-nuts
Hi,

On Nov 29, 11:05 pm, j-g-faustus <johannes.fries...@gmail.com> wrote:
> > "int" and "MyInt" are both named types, so this sentence
> > doesn't apply in that case.
>
> You are saying that 'int' is a named type while 'map[int]int' is not?

"map[int]int" is something composed. You can not expect it to behave
like say "int".
If someone gives a name to a type that is "int" - say "foo" - it is
something different than "int".
So also "map[int]foo" is not the same as "map[int]int".

> I thought all the primitive types - bool, string, int etc. - were
> unnamed, and named types were those renamed by the programmer rather
> than supplied by the language? I was apparently wrong.

I'd not even try to start to think of, if you would be right.

> So let me try a second guess:
> * all primitive types are named types

The definition of "primitive types" could be ambiguous. I'm not sure
what means

const WIDTH_DENSITY = 10000

there. The spec says:

"Constant expressions may contain only constant operands and are
evaluated at compile-time.

Untyped boolean, numeric, and string constants may be used as operands
wherever it is legal to use an operand of boolean, numeric, or string
type, respectively. Except for shift operations, if the operands of a
binary operation are an untyped integer constant and an untyped
floating-point constant, the integer constant is converted to an
untyped floating-point constant (relevant for / and %).

..."

So there is a "type-shift" ;)

> * all types named by the developer are named types (obviously)

Yes.

> * the term "unnamed type" is reserved for anonymous composite types:
> interfaces, structs, function types, arrays, slices, maps and
> channels.
>
> Is this correct?

Yes, this is how I understood it.

Regards,
-Helmar
Reply all
Reply to author
Forward
0 new messages