Variadic Arguments and Interfaces

6,141 views
Skip to first unread message

Paddy Foran

unread,
Sep 7, 2012, 4:45:07 PM9/7/12
to golang-nuts
Consider the following:

In package fmt: func Println(a …interface{})

One would think the following code would work:

func main() {
testslice := []string { "this", "is", "a", "test" }
fmt.Println(testslice…)
}

One would subsequently be met with "cannot use testslice (type []string) as type []interface {} in function argument" (http://play.golang.org/p/H3349TDJnS)

On the other hand, if one were to try:

func print(words …string) {
for _, word := range words {
fmt.Printf("%s", word)
}
}

func main() {
testslice := []string { "this", "is", "a", "test" }
print(testslice…)
}

Everything works as expected (http://play.golang.org/p/1ZnIwge19V). Can anyone explain why the empty interface in variadic parameters prevents me from using argument expansion?

God, I hope I used the right names for all these things.

Rob Pike

unread,
Sep 7, 2012, 4:47:55 PM9/7/12
to Paddy Foran, golang-nuts
[]interface{} and []string are different types. You can only do the
... thing for Printf if the value is of type []interface{}. It's that
simple.

-rob

Rémy Oudompheng

unread,
Sep 7, 2012, 4:48:17 PM9/7/12
to Paddy Foran, golang-nuts
On 2012/9/7 Paddy Foran <foran...@gmail.com> wrote:
> Everything works as expected (http://play.golang.org/p/1ZnIwge19V). Can
> anyone explain why the empty interface in variadic parameters prevents me
> from using argument expansion?
>
> God, I hope I used the right names for all these things.

Variadic functions are syntactic sugar for functions taking a slice
argument. fmt.Printxx take a []interface{} argument, and you try to
give it a []string, which is different.

It is however possible to pass in a []interface{} manually filled with
strings, such as []interface{}{"hello", "world"}, but in general,
direct conversion from []string to []interface{} is not possible.

This a FAQ: http://golang.org/doc/go_faq.html#convert_slice_of_interface
Maybe it could be enriched with the example of variadic functions.

Rémy.

Paddy Foran

unread,
Sep 7, 2012, 4:55:06 PM9/7/12
to Rémy Oudompheng, golang-nuts
Thanks Rob & Rémy for the quick clarification. This is something I should probably know by now, but I'll ask the dumb question.

I was under the impression that interface{} would match every type. I would therefore expect []interface{} to match a slice of any type. Is that not the case? If not, why not? Where am I going wrong in my assumption?

Rémy Oudompheng

unread,
Sep 7, 2012, 4:59:33 PM9/7/12
to Paddy Foran, golang-nuts
On 2012/9/7 Paddy Foran <foran...@gmail.com> wrote:
> Thanks Rob & Rémy for the quick clarification. This is something I should
> probably know by now, but I'll ask the dumb question.
>
> I was under the impression that interface{} would match every type. I would
> therefore expect []interface{} to match a slice of any type. Is that not the
> case? If not, why not? Where am I going wrong in my assumption?

Slice types don't "match" anything, they are just slices.

Rémy.

Rob Pike

unread,
Sep 7, 2012, 5:00:22 PM9/7/12
to Rémy Oudompheng, Paddy Foran, golang-nuts
Your question is answered by the FAQ entry.

-rob

Paddy Foran

unread,
Sep 7, 2012, 5:20:45 PM9/7/12
to Rob Pike, Rémy Oudompheng, golang-nuts
I understand that it doesn't work, that I need to manually convert the slices for it to work. I understand that it's an issue with how things are stored in memory. I just couldn't wrap my head around the higher level design reason for this, as it clashed with my understanding of slices and interfaces. After some thinking, I think I understand.

Slices of objects are slices first. The interfaces in a slice don't fulfill the types in another slice (even if the type implements the interface, as string implements interface{}) because at the type comparison level, the check to see if a type implements an interface isn't done. As far as the type comparison is concerned, interface{} is just another type of slice, which doesn't match any type of slice besides interface{}. This FAQ was a little more helpful (if I understand correctly): http://golang.org/doc/go_faq.html#t_and_equal_interface

Just had to switch my thinking from "interface{} is a stand-in for a type" to "interface{} is a type".

Thanks for the guidance.

Patrick Mylund Nielsen

unread,
Sep 8, 2012, 1:45:39 AM9/8/12
to Paddy Foran, Rémy Oudompheng, golang-nuts
[]Foo, []Bar and []interface{} all implement interface{}. []interface{} is (specifically) a slice of interface{}

Rémy Oudompheng

unread,
Sep 8, 2012, 1:48:41 AM9/8/12
to Paddy Foran, Rob Pike, golang-nuts
On 2012/9/7 Paddy Foran <foran...@gmail.com> wrote:
> I understand that it doesn't work, that I need to manually convert the
> slices for it to work.

Note that you can use:

words := []string{"hello", "world"}
fmt.Println(strings.Join(words, " "))

to print space-separated words. No manual conversion of slices involved here.

Rémy.

Jesse McNelis

unread,
Sep 8, 2012, 2:09:19 AM9/8/12
to Paddy Foran, golang-nuts
On Sat, Sep 8, 2012 at 7:20 AM, Paddy Foran <foran...@gmail.com> wrote:
> Just had to switch my thinking from "interface{} is a stand-in for a type"
> to "interface{} is a type".
>

A lot of people have this confusion until they reach this issue.
The fact that conversions to interfaces is that only place where Go
does implicit conversions allows people to remain confused about what
interfaces really are for quite a while.

If this example isn't in the Go tour it really should be.

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

Paddy Foran

unread,
Sep 8, 2012, 7:34:41 AM9/8/12
to Rémy Oudompheng, golang-nuts
It was definitely a contrived example. Someone was asking about what the ellipsis meant in Go, and I thought the Println() example would be clearer than the append example, only to discover it didn't work. At which point, curiosity demanded I find out why.

Thanks everyone for all the help. Appreciated.

Saied Seghatoleslami

unread,
May 17, 2020, 6:27:47 PM5/17/20
to golang-nuts
I hate to dig up something from 2012, but I have come across a similar issue where I can use an explanation.  The signature of the Query function in the sql package is:

func (db *DB) Query(query string, args ...interface{}) (*Rows, error)

so, one would assume that passing something like this  for args would work (Active is bool and Role is a string:

var cond = []interface{}{exchData.Active, exchData.Role}

but it does not, it results in this error:

sql: converting argument $1 type: unsupported type []interface {}, a slice of interface


I suspect there is a good explanation for this that I do not get.

Steven Hartland

unread,
May 17, 2020, 6:39:07 PM5/17/20
to golan...@googlegroups.com
Did you use the correct calling convension e.g.
db.Query(query, cond...)

The ... makes the slice variadic, passing echData.Active, exchData.Role instead of just a interface slice
--
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/1cc28db0-98c6-49cd-bd3e-7752ef2b5328%40googlegroups.com.

Saied Seghatoleslami

unread,
May 17, 2020, 7:05:30 PM5/17/20
to golang-nuts
I have it working well by listing the individual conditions.  But I have a bunch of functions that do similar things (authenticate a user based on their email and password, get a list of users based on role and active status, get an individual user based on ID, etc.) and I was looking to combine them into a more generalized function.  So far I have not found a way.
To unsubscribe from this group and stop receiving emails from it, send an email to golan...@googlegroups.com.

Saied Seghatoleslami

unread,
May 17, 2020, 7:40:32 PM5/17/20
to golang-nuts
I found this article by Nick Gauthier from 2016.  https://www.meetspaceapp.com/2016/05/23/writing-a-data-mapper-in-go-without-an-orm.html.  The original idea is contributed to Martin Fowler.

Someone else has solved this problem before.  


On Friday, September 7, 2012 at 4:45:07 PM UTC-4, Paddy Foran wrote:
Reply all
Reply to author
Forward
0 new messages