Appending to a slice of interfaces with variadic arguments

4,128 views
Skip to first unread message

Francesc Campoy Flores

unread,
Oct 23, 2012, 5:22:30 PM10/23/12
to golan...@googlegroups.com
Hi,

I was recently surprised with a compilation error trying to append all the elements of a slice of structs to a slice of interfaces.


Why is line 25 correct, but not line 26?

--
Francesc

andrey mirtchovski

unread,
Oct 23, 2012, 5:40:41 PM10/23/12
to Francesc Campoy Flores, golan...@googlegroups.com
> Why is line 25 correct, but not line 26?

for the same reason it won't work here:
http://play.golang.org/p/hvlLY7DTY_. go doesn't implicitly convert []T
to []interface{} because that involves introspection for each element
in the array (you also can't do []T1(x) on x = []T) . you'll have to
do it manually in a loop.

Rémy Oudompheng

unread,
Oct 23, 2012, 5:41:30 PM10/23/12
to Francesc Campoy Flores, golan...@googlegroups.com
The signature of append-for-slices-of-Abser is:

append(s []Abser, t ...Abser) []Abser

The second argument can be a Point because Points are implciitly
converted to Absers if needed (assignability).
The second argument cannot be a []Point because the convention for
variadic arguments is that t is actually an []Abser (and the variadic
syntax is sugar for a []Abser literal). And you cannot pass a []Point
and expect it to b e converted to []Abser.

Rémy.

Francesc Campoy Flores

unread,
Oct 23, 2012, 5:57:31 PM10/23/12
to Rémy Oudompheng, golan...@googlegroups.com
I understand the reasons here, but I still think it can get pretty confusing. And the specs don't really help.


When the function is called with a slice as the variadic argument, the passed slice must be assignable to []T (and not only every single element to T).

Should I open a bug about it? Or am I the only one concerned about this?

Cheers,

Francesc

--
--
Francesc

Nigel Tao

unread,
Oct 23, 2012, 8:00:14 PM10/23/12
to Francesc Campoy Flores, Rémy Oudompheng, golan...@googlegroups.com
On 24 October 2012 08:57, Francesc Campoy Flores <cam...@golang.org> wrote:
> Should I open a bug about it? Or am I the only one concerned about this?

It is not a bug. It's a FAQ.
http://golang.org/doc/go_faq.html#convert_slice_of_interface

As Paddy Foran said, "switch [your] thinking from "interface{} is a
stand-in for a type" to "interface{} is a type"."
https://groups.google.com/forum/#!msg/golang-nuts/0qWnorUuct8/CGMaVFFyZEUJ

Francesc Campoy Flores

unread,
Oct 23, 2012, 8:04:59 PM10/23/12
to Nigel Tao, Rémy Oudompheng, golan...@googlegroups.com
I'm not talking about the conversion of the slices, I understand that and I would not say it's a bug.

I'm talking about the fact that while:

s := []int{1, 2, 3}
fmt.Println(s[0], s[1], s[2])

works

fmt.Println(s...)

fails.

From my point of view they should be semantically identical, and the specs don't clarify anything about this case
--
--
Francesc

Nigel Tao

unread,
Oct 23, 2012, 8:18:51 PM10/23/12
to Francesc Campoy Flores, Rémy Oudompheng, golan...@googlegroups.com
On 24 October 2012 11:04, Francesc Campoy Flores <cam...@golang.org> wrote:
> From my point of view they should be semantically identical, and the specs
> don't clarify anything about this case

I think conversion of slices and the variadic args are the same thing.
In both cases, you have a []S and you're trying to pass it to
something that wants a []I, for some struct type S and interface type
I.

I think the spec is pretty clear.
http://golang.org/ref/spec#Passing_arguments_to_..._parameters says
"If the final argument is assignable to a slice type []T, it may be
passed unchanged as the value for a ...T parameter if the argument is
followed by ...."

A []S is not assignable to a []I.

Matt Kane's Brain

unread,
Oct 23, 2012, 8:28:12 PM10/23/12
to Francesc Campoy Flores, Nigel Tao, Rémy Oudompheng, golan...@googlegroups.com
They aren't semantically identical.

fmt.Println(s[0], s[1], s[2]) is semantically identical to making a
new slice with the arguments and throwing it away after the call i.e.
fmt.Println([]int{s[0], s[1], s[2]}).

If you pass in a slice instead of individual arguments, the slice is mutable:
http://play.golang.org/p/8xalhkK5si

The wording in the spec doesn't make that consequence obvious.

On Tue, Oct 23, 2012 at 8:04 PM, Francesc Campoy Flores
<cam...@golang.org> wrote:
> From my point of view they should be semantically identical, and the specs
> don't clarify anything about this case
--
matt kane's brain
http://hydrogenproject.com

Dumitru Ungureanu

unread,
Oct 24, 2012, 3:19:53 AM10/24/12
to golan...@googlegroups.com, Rémy Oudompheng, simon...@googlemail.com
On Wednesday, October 24, 2012 2:41:44 AM UTC+3, simon...@googlemail.com wrote:
(this is from a while back, i didn't post before because i wanted to try to find a fix.)


This may be explaining a few things, perhaps:

package main

import "fmt"

func main() {
    x := []int{9, 1, 2}              // a slice of int: []int
    s := make([]interface{}, len(x)) // a slice of interface{}: []interface{}
    for i, v := range x {            // make every int an interface{}
        s[i] = v
    }
    fmt.Println("x = ", x)
    fmt.Printf("s... : s[0] = %v\t s[1] = %v\t s[2] = %v\n", s...)

}
 

yy

unread,
Oct 24, 2012, 7:34:16 AM10/24/12
to Matt Kane's Brain, Francesc Campoy Flores, Nigel Tao, Rémy Oudompheng, golan...@googlegroups.com
On 24 October 2012 02:28, Matt Kane's Brain
<mkb-...@hydrogenproject.com> wrote:
> fmt.Println(s[0], s[1], s[2]) is semantically identical to making a
> new slice with the arguments and throwing it away after the call i.e.
> fmt.Println([]int{s[0], s[1], s[2]}).

Actually, that should be:

fmt.Println([]interface{}{s[0], s[1], s[2]}...)


--
- yiyus || JGL .
Reply all
Reply to author
Forward
0 new messages