Empty interface{} and type switch

1,546 views
Skip to first unread message

Abhijit Kadam

unread,
Jan 7, 2014, 1:03:48 PM1/7/14
to golan...@googlegroups.com
I am looking into empty interface type switch and not getting what is happening here. The program has 2 types(Type1 & Type2) and in func Process if I pass Type1 instance then inside it, once the type is deducted to Type1 further how it can be switched to Type2 as shown below? The interface{} would initially have pair of type 'Type1' and value 't' that is passed from main which is of Type1 instance. If the Type1 is passed as pointer and asserted (switched) as pointer then this would not work. Getting confused

Output:
Type of t:  main.Type1
Type of v:  main.Type2 
 {type2}
{type1 32}

Program:

package main

import (
"fmt"
"reflect"
)

type Type1 struct{
Name string
count int
}

type Type2 struct{
Name string
}

func Process(t interface{}){
fmt.Println("Type of t: ", reflect.TypeOf(t))

v,_ := t.(Type2) // How ??

v.Name = "type2"
fmt.Println("Type of v: ", reflect.TypeOf(v),"\n", v)
}

func main() {
t := Type1{Name:"type1", count:32}
Process(t)
fmt.Println(t)
}

chris dollin

unread,
Jan 7, 2014, 1:15:04 PM1/7/14
to Abhijit Kadam, golang-nuts

you have ignored the boolean returned from thebvtype assertion, which will be false. v will be the zero value of type2.

chris onna bus

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Thomas Bushnell, BSG

unread,
Jan 7, 2014, 1:20:43 PM1/7/14
to Abhijit Kadam, golang-nuts
It is almost always better to use interfaces properly, than to use interface{} with typeswitch.


Abhijit Kadam

unread,
Jan 7, 2014, 1:33:39 PM1/7/14
to golan...@googlegroups.com, Abhijit Kadam, ehog....@googlemail.com
The doc says that if assertion fails it will exist and will be zero value. so in this case Type2 value is not paired in any sense with interface, I mean with the value and type pair that interface holds?

Abhijit Kadam

unread,
Jan 7, 2014, 1:42:46 PM1/7/14
to golan...@googlegroups.com, Abhijit Kadam
Agreed. I am looking into how things are implemented. 

Carlos Castillo

unread,
Jan 7, 2014, 2:30:21 PM1/7/14
to golan...@googlegroups.com
There are two forms of type assertions (http://golang.org/ref/spec#Type_assertions):

 x := v.(Type) // Panic on failure
 y, ok := v.(Type) // ok = false on failure, y = zero value of Type

You used the second kind, which when the assertion fails doesn't panic, and instead sets the first value in the assignment to the zero value, and sets the second to false. Since you ignored the second value, you didn't check if the assertion failed, and just used the zero value (as chris said). If you used the first form, you would have gotten a panic at run-time, or if you had properly checked the 2nd value in the second form, you could handle yourself the type mismatch.

Abhijit Kadam

unread,
Jan 8, 2014, 1:32:54 AM1/8/14
to golan...@googlegroups.com
Thanks. Another thing when using type assertion like here: http://play.golang.org/p/7UrKzGQaIp
var t Type1 = "type1val"

var i interface{} = t
t1 := i.(Type1)
fmt.Println(t1.GetValue())

// Why this doesn't work?
//fmt.Println(i.(Type1).GetValue())

Gerard

unread,
Jan 8, 2014, 2:55:28 AM1/8/14
to golan...@googlegroups.com
This is a more "go-ish" simplification of your program. See link.

Func String() matches an interface. To be specific it matches fmt.Stringer.

The fmt Print family automatically recognises fmt.Stringer, so if your type contains a String() function it works.

I know my answer doesn't answer your question, but it is a different thought.

Jan Mercl

unread,
Jan 8, 2014, 2:57:37 AM1/8/14
to Abhijit Kadam, golang-nuts
On Wed, Jan 8, 2014 at 7:32 AM, Abhijit Kadam <abhij...@gmail.com> wrote:
> Thanks. Another thing when using type assertion like here:
> http://play.golang.org/p/7UrKzGQaIp
> var t Type1 = "type1val"
>
> var i interface{} = t
> t1 := i.(Type1)
> fmt.Println(t1.GetValue())
>
> // Why this doesn't work?
> //fmt.Println(i.(Type1).GetValue())
>

What does "doesn't work" stand for? And where is the complete
compilable program?

Otherwise one has to only guess, but then it seems to work okay:
http://play.golang.org/p/I9AhXtWExC

-j

Abhijit Kadam

unread,
Jan 8, 2014, 3:04:03 AM1/8/14
to golan...@googlegroups.com, Abhijit Kadam
Jan, the receiver Type1 should be pointer; then try. Also I mentioned the link that runs http://play.golang.org/p/7UrKzGQaIp , didn't I?

Jan Mercl

unread,
Jan 8, 2014, 3:12:53 AM1/8/14
to Abhijit Kadam, golang-nuts
On Wed, Jan 8, 2014 at 9:04 AM, Abhijit Kadam <abhij...@gmail.com> wrote:
> Jan, the receiver Type1 should be pointer; then try. Also I mentioned the
> link that runs http://play.golang.org/p/7UrKzGQaIp , didn't I?

You did. I obviously can't read sometimes :-(

Anyway, the problem is that a standalone value (the result of the type
assertion) has no "home"* and thus no address which can be taken. Give
it a home (eg. assign it to a variable) and it works - that's the
first case of your 't1 := i.(Type1); fmt.Println(t1.GetValue())'.

*: like in

func f() int { return 42 }

var p = &f()

-j

Volker Dobler

unread,
Jan 8, 2014, 3:17:59 AM1/8/14
to golan...@googlegroups.com, Abhijit Kadam
Am Mittwoch, 8. Januar 2014 09:04:03 UTC+1 schrieb Abhijit Kadam:
Jan, the receiver Type1 should be pointer; then try. Also I mentioned the link that runs http://play.golang.org/p/7UrKzGQaIp , didn't I?

The error message is pretty clear: No pointer methods are allowed here.
Why? Pointer methods are used (often) to modify their receiver. Your
receiver here is what comes out of a type assertion and it is basically
always wrong to modify this (as it is a copy). So no pointer methods here,
even if you are not modifying your receiver.

V.

Abhijit Kadam

unread,
Jan 8, 2014, 3:30:41 AM1/8/14
to golan...@googlegroups.com, Abhijit Kadam
Pointer methods can also be used to prevent copy in case the object is big enough. Also I can call the method anyway on next line so why the compiler not compile things as if done separately? 

What comes out of type assertion is a copy! is new learning for me. I thought interface{} hold type info and value object and type assertion would cast to that object if proper type is used for assertion. Why a copy? If I want to pass objects for processing into func that takes interface{} then changes will be done in copy and I need to return the copy by pointer then in such cases?

chris dollin

unread,
Jan 8, 2014, 4:03:30 AM1/8/14
to Abhijit Kadam, golang-nuts
On 8 January 2014 08:30, Abhijit Kadam <abhij...@gmail.com> wrote:

What comes out of type assertion is a copy! is new learning for me. I thought interface{} hold type info and value object and type assertion would cast to that object if proper type is used for assertion.

(TERMINOLOGY: There are no "casts" in Go.)

Why a copy?

Go copies all over the place, there's no special exception for type
assertions. If what came out of the type assertion shared the value
in the interface object, you could change it, and all the copies of that
interface value would see the change -- that's not Go behaviour, you
have to be explicit with pointers to do that.
 
If I want to pass objects for processing into func that takes interface{} then changes will be done in copy and I need to return the copy by pointer then in such cases?

If you want to pass something into a function and make changes to it
that will be visible in the original passed-in value, pointers will have
to be involved /somehow/, although they might be the hidden pointers
in a map or slice.

If you're passing in a value to an interface{}, and then type-asserting
the interface{} to something and changing that something and then
trying to smuggle that change back into the original value, I suspect
you have a design issue that needs facing up to.

Chris

--
Chris "allusive" Dollin

Martin Schnabel

unread,
Jan 8, 2014, 4:08:44 AM1/8/14
to golan...@googlegroups.com
On 01/08/2014 09:30 AM, Abhijit Kadam wrote:
> Pointer methods can also be used to prevent copy in case the object is
> big enough. Also I can call the method anyway on next line so why the
> compiler not compile things as if done separately?
>
> What comes out of type assertion is a copy!

If you put a struct value into an interface you get a copy of the same.
But if you put a pointer value to the same struct value into an
interface you get back a copy of that pointer value.

> is new learning for me. I
> thought interface{} hold type info and value object and type assertion
> would cast to that object if proper type is used for assertion. Why a
> copy? If I want to pass objects for processing into func that takes
> interface{} then changes will be done in copy and I need to return the
> copy by pointer then in such cases?
>
No just assign the pointer to the value instead of the value itself to
the interface.

You can also define an interface type and get rid of the type assertion.

http://play.golang.org/p/lQDb9iA2l_

Volker Dobler

unread,
Jan 8, 2014, 4:37:01 AM1/8/14
to golan...@googlegroups.com, Abhijit Kadam
Am Mittwoch, 8. Januar 2014 09:30:41 UTC+1 schrieb Abhijit Kadam:
Pointer methods can also be used to prevent copy in case the object is big enough.
Yes: Can. In the sense of "I made realistic benchmarks and measured
them under realistic conditions and using pointer methods seep up
my stuff by 3%". 
 
Also I can call the method anyway on next line so why the compiler not compile things as if done separately?
Of course you can call this method on your now live object
but this would be still wrong (most of the time) but in this case
the wrongness is a bit more obvious (and it is hard to detect
such misuse in the compiler).
 
What comes out of type assertion is a copy! is new learning for me. I thought interface{} hold type info and value object and type assertion would cast to that object if proper type is used for assertion. Why a copy? If I want to pass objects for processing into func that takes interface{} then changes will be done in copy and I need to return the copy by pointer then in such cases?
This may sound harsh, but it is meant a constructive advice:
If you are learning Go you should *not* use interface{} at all.
The empty interface is there because sometimes externalities
force you and with a wall in your back and a knife at your
throat you pull your interface{} and use it.
If your code requires passing different but not arbitrary stuff
around using interface{} you are doing something wrong. 
 
Go is (almost) dead simple here: Everything has copy semantics.
To allow modifications you use pointers explicitly (and the pointers
have copy semantics). Even maps and slices have copy semantics
but their data is accessed via pointers. (This is a simplification but
a reasonable first order approximation.)

Abhijit Kadam

unread,
Jan 8, 2014, 6:12:05 AM1/8/14
to Volker Dobler, golan...@googlegroups.com
From Martin's comment it is clear to me now that if you pass struct value you will get copy, if you pass it by reference the interface holds reference (pointer copy) hence pointing to same object.

With empty interface{} I am not thinking about best practices rather experimenting to understand the interface{} implementation. What bothered me is a runtime check is required to find it something passed as interface{} implements other concrete interface or types.

go doesn't have generic type template func like 

func Filter(t T) bool{
    if t.count > 10{         //t.count field check should be at compile time when func Filter is called
       return true
     }else{
        return false
     }
}

Then call Filter on any type that should have 'count' field

type data struct{
 count int
}

Filter(data{count:10}) //compiler should generate copy of Filter func that satisfies type data

=>
I like most the implicit interface implementation however when looked into interface{} then it was not as clear. Like the 'fmt' package has many functions like Println, Fprintln, etc that takes interface{} and then inside there is a check for whether a passed in type has implemented 'Stringer' interface. By looking at the doc (http://golang.org/pkg/fmt/#Println) I get no idea that interface 'Stringer' is honored inside. How do I know such things. I got to know from slides and blogs about Println using Stringer interface.

Thoughts?
 

chris dollin

unread,
Jan 8, 2014, 6:26:03 AM1/8/14
to Abhijit Kadam, Volker Dobler, golang-nuts
On 8 January 2014 11:12, Abhijit Kadam <abhij...@gmail.com> wrote:


I like most the implicit interface implementation however when looked into interface{} then it was not as clear. Like the 'fmt' package has many functions like Println, Fprintln, etc that takes interface{} and then inside there is a check for whether a passed in type has implemented 'Stringer' interface. By looking at the doc (http://golang.org/pkg/fmt/#Println) I get no idea that interface 'Stringer' is honored inside. How do I know such things.

It's in the documentation but you have to dig a bit.

The package overview says:

    For each Printf-like function, there is also a Print function that

    takes no format and is equivalent to saying %v for every operand. Another

    variant Println inserts blanks between operands and appends a newline.

Under General the overview says:

    %v    the value in a default format.

and futher down:

2. If an operand implements method String() string, that method will be used to convert the object to a string, which will then be formatted as required by the verb (if any).

So Println respects String()string, which is what Stringer is.

Maybe one shouldn't have to dig so hard, but on the other hand,
the big Overview does suggest that there are lots of things to know.

Chris
 
--
Chris "allusive" Dollin

Volker Dobler

unread,
Jan 8, 2014, 7:32:38 AM1/8/14
to golan...@googlegroups.com, Volker Dobler


Am Mittwoch, 8. Januar 2014 12:12:05 UTC+1 schrieb Abhijit Kadam:
From Martin's comment it is clear to me now that if you pass struct value you will get copy, if you pass it by reference the interface holds reference (pointer copy) hence pointing to same object.
In Go there is no such thing like "pass by reference", only pass
by value. You can pass a var i interface{} only by value and this
says nothing about "what this interface{}" holds. I admit I do not
understand your argument.
 
With empty interface{} I am not thinking about best practices rather experimenting to understand the interface{} implementation. What bothered me is a runtime check is required to find it something passed as interface{} implements other concrete interface or types.
stop experimenting.
 
go doesn't have generic type template func like 

func Filter(t T) bool{
    if t.count > 10{         //t.count field check should be at compile time when func Filter is called
       return true
     }else{
        return false
     }
}

Then call Filter on any type that should have 'count' field

type data struct{
 count int
}

Filter(data{count:10}) //compiler should generate copy of Filter func that satisfies type data
I won't follow you on any road to generics.
This horse is dead until some clever new idea emerges.
 
I like most the implicit interface implementation however when looked into interface{} then it was not as clear. Like the 'fmt' package has many functions like Println, Fprintln, etc that takes interface{} and then inside there is a check for whether a passed in type has implemented 'Stringer' interface. By looking at the doc (http://golang.org/pkg/fmt/#Println) I get no idea that interface 'Stringer' is honored inside. How do I know such things. I got to know from slides and blogs about Println using Stringer interface.
As said: You should never use interface{}.

And for the fmt package: Yes is does some magic and the documentation
could be more explicit (and longer) but it is documented and fmt is one of
those things which have to cope with arbitrary stuff. 
 
V.

chris dollin

unread,
Jan 8, 2014, 8:03:01 AM1/8/14
to Volker Dobler, golang-nuts
On 8 January 2014 12:32, Volker Dobler <dr.volke...@gmail.com> wrote:

Am Mittwoch, 8. Januar 2014 12:12:05 UTC+1 schrieb Abhijit Kadam:
From Martin's comment it is clear to me now that if you pass struct value you will get copy, if you pass it by reference the interface holds reference (pointer copy) hence pointing to same object.
In Go there is no such thing like "pass by reference", only pass
by value.

Yes -- I think (hope) that by "pass it by reference" Abhijit means "pass a
pointer to it".

 Chris

--
Chris "allusive" Dollin

Abhijit Kadam

unread,
Jan 8, 2014, 8:36:33 AM1/8/14
to golan...@googlegroups.com, Volker Dobler, ehog....@googlemail.com
Yes, obviously I mean pass by pointer as also mentioned by mb0(Martin) above. Also hope in golang some meta programming with generics is there in near future.

I saw fmt package using many interace{}. Also though of scenario where you have to use reflection to know types and do invocation as done in most frameworks that uses dependency injection, handlers, filters, aspects like things.
Reply all
Reply to author
Forward
0 new messages