Interfaces & casting types.

11,538 views
Skip to first unread message

Dougx

unread,
Feb 14, 2011, 8:49:18 PM2/14/11
to golang-nuts
Mm... having a little trouble using interfaces. I must be doing
something wrong, can someone clarify?

Basically, I want to do this:

TypeA -> Implements InterfaceA
TypeB -> Implements InterfaceA
TypeC -> Implements InterfaceA
new Factory
factory.get(type) -> Returns the appropriate implementation based on
the key.

However, just starting out I'm hitting an error:
lib.go:21: cannot use b (type *Blob) as type *Component in assignment

From this code:

// All components require this.
type Component interface {
Factory() *Component
}

type Blob struct {
x int
}

func (self *Blob) Factory() *Component {
return(nil)
}

var b *Blob = new(Blob)
var c *Component = b

I see in the go for c programmers it says:
Go does not support implicit type conversion. Operations that mix
different types require casts (called conversions in Go).

...but no examples, or details on how to do that. The closest I've
seen is an int cast int(x), but trying:

var c *Component = Component(b)
--> lib.go:21: cannot use Component(b) (type Component) as type
*Component in assignment: need type assertion

and:

var c *Component = *Component(b)
--> lib.go:21: invalid indirect of Component(b) (type Component)

So... what's the syntax to do that correctly?

thanks!

David Symonds

unread,
Feb 14, 2011, 9:10:31 PM2/14/11
to Dougx, golang-nuts
Don't use *Component, use Component.

b := new(Blob)
var c Component = b

Dougx

unread,
Feb 14, 2011, 10:13:38 PM2/14/11
to golang-nuts
Oh, so an interface is _already_ a pointer to a struct.

So what I was trying to do was the equivalent in c of:
struct Blob *b = ...;
struct Component **c = (struct Component **) b;

I wish the effective go section on interfaces had a simple example
explaining this.

eg.

type TypeA interface {
Get() int
}

type StructA struct {
int i
}

func (self *StructA) Get() int {
return self.i
}

func main() {

// Instance
var a StructA
a.i = 10

// Reference
var b *StructA = new(StructA)
(*b).i = 10

// Interface
var c TypeA = &a
var d TypeA = b
fmt.Printf("%d\n", c.Get())
fmt.Printf("%d\n", d.Get())

// Interface reference
var e *TypeA = &c
value := (*e).Get()
fmt.Printf("%d\n", value)
}

Thanks~

~
Doug.

David Symonds

unread,
Feb 14, 2011, 11:01:27 PM2/14/11
to Dougx, golang-nuts
On Tue, Feb 15, 2011 at 2:13 PM, Dougx <douglas...@gmail.com> wrote:

> Oh, so an interface is _already_ a pointer to a struct.

No, that's not the right way to look at it. In addition to Rob's
"interfaces are not pointers" message in the other thread, interfaces
can contain lots of different types, including pointers to structs,
direct structs, ints, bools, strings, maps, etc. The principle of an
interface concerns the methods attached to a type T, not what type T
is.


Dave.

Dougx

unread,
Feb 14, 2011, 11:15:35 PM2/14/11
to golang-nuts
I see. So it's just a case of strange syntax.

In every other language I've used you have distinct types:
- primitive
- pointer

They are not compatible.

Attempting to do either of these should yield an error:
- primitive x = pointer y
- pointer x = primitive y

Interfaces are strange.

var a *StructA = ...
var b InterfaceA = b

may be shorthand for:

b.setMyInnerInterfaceReferenceToObject(b)

But it doesn't change the fact that a * type object has just been
converted into a primitive.

This is counter intuitive.

~
Doug.

On Feb 15, 12:01 pm, David Symonds <dsymo...@golang.org> wrote:

Russ Cox

unread,
Feb 14, 2011, 11:23:29 PM2/14/11
to Dougx, golang-nuts
On Mon, Feb 14, 2011 at 23:15, Dougx <douglas...@gmail.com> wrote:
> I see. So it's just a case of strange syntax.

No, it's a case of you don't understand the semantics.
That's an important distinction.

> In every other language I've used you have distinct types:
> - primitive
> - pointer
>
> They are not compatible.

A pointer is one kind of type.
A struct is another kind of type.
An integer is another kind of type.
A floating point number is another kind of type.
A boolean is another kind of type.

All of these types can have methods defined on them.

An interface type is defined by a set of methods.
Any value that implements the methods can be
assigned to an interface value of that type.

Like David said, an interface value is like a box
in which you can store any value that has the
necessary methods.

If a pointer type implements the methods,
you can store a value of that type in the interface value.
If a struct type implements the methods,
you can store a value of that type in the interface value.
If an integer type implements the methods,
you can store a value of that type in the interface value.
If a floating point type implements the methods,
you can store a value of that type in the interface value.
If a boolean type implements the methods,
you can store a value of that type in the interface value.

> But it doesn't change the fact that a * type object has just been
> converted into a primitive.

A value of pointer type has been stored into an interface value.
Calls to methods on that interface value will use that pointer
value as the receiver argument.

If you replace pointer by integer in that last paragraph, it still
works. Same for floating point, boolean, struct (and map, channel,
and function, but I've been ignoring those).

var p *int
var i int
var f float64
var b bool

var x interface{}

x = p
println(p == x.(*int))
x = i
println(i == x.(int))
x = f
println(f == x.(float64))
x = b
println(b == x.(bool))

Russ

Steven

unread,
Feb 14, 2011, 11:37:54 PM2/14/11
to Dougx, golang-nuts
On Mon, Feb 14, 2011 at 11:15 PM, Dougx <douglas...@gmail.com> wrote:
I see. So it's just a case of strange syntax.

In every other language I've used you have distinct types:
- primitive
- pointer

They are not compatible.

Attempting to do either of these should yield an error:
- primitive x = pointer y
- pointer x = primitive y

Interfaces are strange.

var a *StructA = ...
var b InterfaceA = b

may be shorthand for:

b.setMyInnerInterfaceReferenceToObject(b)

But it doesn't change the fact that a * type object has just been
converted into a primitive.

This is counter intuitive.

Just to add: Go doesn't distinguish between "primitive" and "pointer" types. There are different kinds of types, and pointers are just one of them. They just happen to refer to values of other types. A slice also refers to many values of another type. A struct can contain a pointer, so it can refer to a value of another type. Pointers aren't special. They're just a particular kind of value.

Dougx

unread,
Feb 15, 2011, 6:08:45 AM2/15/11
to golan...@googlegroups.com, Dougx
Fair enough~

I maintain that if the language allows a type is explicitly declared using *'s to indicate it's 'pointer level' then just as I can't assign a **Interface value to a *Interface, or a ****Interface to a **Interface, I shouldn't be able to assign a *Interface to an Interface, without some kind of compiler warning or special cast.

I mean, technically I can do this right?

package main

type TypeA interface {}

func main() {
  var a TypeA
  var b *TypeA
  b = &a
  a = b 
  a = &a
  b = &a
}

Not technically wrong.

Just syntactically, odd. Reading code like this makes me want to go back and program in perl again (really no).

roger peppe

unread,
Feb 15, 2011, 6:30:50 AM2/15/11
to golan...@googlegroups.com, Dougx
On 15 February 2011 11:08, Dougx <douglas...@gmail.com> wrote:
> Fair enough~
> I maintain that if the language allows a type is explicitly declared using
> *'s to indicate it's 'pointer level' then just as I can't assign a
> **Interface value to a *Interface, or a ****Interface to a **Interface, I
> shouldn't be able to assign a *Interface to an Interface, without some kind
> of compiler warning or special cast.

you can't do this in general.

> I mean, technically I can do this right?
> package main
> type TypeA interface {}
> func main() {
>   var a TypeA
>   var b *TypeA
>   b = &a
>   a = b
>   a = &a
>   b = &a
> }
> Not technically wrong.

the only reason you can do this is because you're using
not just any old interface type, but interface{}, which can
hold any value at all, including a pointer to itself.

it's like a safer version of C's void*.
complaining about the above is like complaining
about the following bit of (correct) C code:

typedef void* TypeA;
void f(){
TypeA a;
TypeA *b;


b = &a;
a = b;
a = &a;

b = &a;
}

it's made safe by the fact that it knows what type is
stored inside it.

in fact in your example you don't even need
to use interface types. you could define TypeA
as
type TypeA *TypeA

and it works ok.

chris dollin

unread,
Feb 15, 2011, 6:32:17 AM2/15/11
to golan...@googlegroups.com, Dougx
On 15 February 2011 11:08, Dougx <douglas...@gmail.com> wrote:
> Fair enough~
> I maintain that if the language allows a type is explicitly declared using
> *'s to indicate it's 'pointer level' then just as I can't assign a
> **Interface value to a *Interface, or a ****Interface to a **Interface, I
> shouldn't be able to assign a *Interface to an Interface, without some kind
> of compiler warning or special cast.

If the value doesn't satisfy the interface, then you can't do it, and
if it does, you can, because there's no problem. That's different from
the pointer case, because X and *X have different behaviours.

> I mean, technically I can do this right?
> package main
> type TypeA interface {}
> func main() {
>   var a TypeA
>   var b *TypeA
>   b = &a
>   a = b
>   a = &a
>   b = &a
> }
> Not technically wrong.

It's not "Not technically wrong". It's just "Not wrong". (Did you mean
to write "b = &a" twice?)

`a` is a variable that can hold any value with at least zero methods,
and all the values you assign to it have that many, so it's OK.

All the values you assign to `b` are pointer-to-TypeA values, so
there's no problem there either.

If you were to try `b = a` you'd get:

cannot use a (type TypeA) as type *TypeA in assignment: need type assertion

so the language is preventing things that I think you think need
preventing.

> Just syntactically, odd.

There's nothing /syntactically/ odd about it at all. And the type
system is quite straightforward.

--
Chris "allusive" Dollin

Dougx

unread,
Feb 15, 2011, 6:40:48 AM2/15/11
to golan...@googlegroups.com, Dougx
This is exactly what I mean.

In c, it requires that you have explicitly defined the type as a void * (note the >>> * in the definition)

You are assigned from a pointer type to a pointer type when you go:
a = b

In go, the type definition does not include a *, and so it is (in my, personal view) not clear that the assignment should be possible.

*shrug* Sorry if I've ruffled any feathers; I quite like go, I just find this particular part of the syntax odd. 
If you don't, that's cool. I'm happy to disagree.

Cheers,
Doug.


Jessta

unread,
Feb 15, 2011, 6:48:55 AM2/15/11
to golan...@googlegroups.com, Dougx
On Tue, Feb 15, 2011 at 10:08 PM, Dougx <douglas...@gmail.com> wrote:
> Fair enough~
> I maintain that if the language allows a type is explicitly declared using
> *'s to indicate it's 'pointer level' then just as I can't assign a
> **Interface value to a *Interface, or a ****Interface to a **Interface, I
> shouldn't be able to assign a *Interface to an Interface, without some kind
> of compiler warning or special cast.

Yeah, it's syntactic sugar.
They could have made you do the conversion explicitly, eg.


type TypeA interface{}
func main(){
var a TypeA

b := 1
a = TypeA(b)
}

But interfaces are used so often, all over the place that it starts to
get silly. Since a type is never going to be the interface type
required by a function a conversion would always be needed. This gets
in the way of the idea you're trying to convey.
eg.
io.Copy(io.Writer(buffer),io.Reader(someotherbuffer))

It starts to look really horrible. The compiler knows that buffer has
the methods for an io.Writer and the programmer knows that's what he
wants to do. So it's a lot of clutter for no reason.

So a simple rule, you can assign any type to an interface which
satisfies it's method set.
Everyone remembers it, it's not confusing once you know it and
everything gets a bit clearer.

- jessta
--
=====================
http://jessta.id.au

roger peppe

unread,
Feb 15, 2011, 6:50:16 AM2/15/11
to golan...@googlegroups.com, Dougx
On 15 February 2011 11:40, Dougx <douglas...@gmail.com> wrote:
> This is exactly what I mean.
> In c, it requires that you have explicitly defined the type as a void *
> (note the >>> * in the definition)
> You are assigned from a pointer type to a pointer type when you go:
> a = b

it doesn't work if TypeA is defined as any pointer type other
than void*. that's because void* is special to the C compiler - it's allowed
to hold any pointer type (except function pointers, but that's
another story).

Go's interfaces are also special - they are allowed to hold any type
at all as long as the type implements the given interface.
since interface{} has no methods any type at all can
be held in it. including *interface{}.

an interface value doesn't *point* to a value; it *holds*
the value.

Gustavo Niemeyer

unread,
Feb 15, 2011, 7:31:30 AM2/15/11
to golan...@googlegroups.com, Dougx
> *shrug* Sorry if I've ruffled any feathers; I quite like go, I just find
> this particular part of the syntax odd.
> If you don't, that's cool. I'm happy to disagree.

You can disagree, of course, but as has been nicely pointed out to you
by others, disagreeing with the *syntax* in this case proves you still
misunderstand the semantics of what is happening.

Consider this line:

var err os.Error = X

This code means: X must have a String() string method to be assigned
to this interface. X itself can be of *any* other type (including
pointers) which has a suitable method String() defined on it. Again,
this same statement will work with pointer and with non-pointer types,
as long as the *respective type* implements the method. An interface
is not a pointer to something. It's a container to a value which has
the required methods declared for its type.

> In c, it requires that you have explicitly defined the type as a void * (note the >>> * in the definition)

It doesn't matter.. void* has vastly different semantics, so it's a
poor analogy.

--
Gustavo Niemeyer
http://niemeyer.net
http://niemeyer.net/blog
http://niemeyer.net/twitter

Reply all
Reply to author
Forward
0 new messages