append() with lists, also, mixing simple and variadic arguments

916 views
Skip to first unread message

Ali Ali

unread,
Jul 13, 2012, 2:33:13 PM7/13/12
to golan...@googlegroups.com
Hi Go-Experts,

I've got tqo questions, somewhat similar. First, documentation of the append() builtin  (if i unserstand it right) lists the  that the two following constructs are possible.

slice = append(slice, elem1, elem2)
slice = append(slice, anotherSlice...)

However, the second one doesnt seem to work in go-1? The following code does not compile:

 list1:=[]string{"1","2","3"}
 list2:=[]string{"6","7","8"}
 list1=append(list1,list2)

"cannot use list2 (type []string) as type string in append"

It can be done in a cycle, with range over list2 and by-element append of course.

Another question -- can I mix normal and variadic arguments, like,

func Check(s string, vars ...string) ( err bool) {
  if s == "one" {
        fmt.Printf("the %s has %d elements\n", s, len(vars) )
        return true
  }
  fmt.Printf("not the one, %v \n", vars)
}

...

ok = Check("one", list2)

This wont compile either: "cannot use list1 (type []string) as type string in function argument"

The question is: Since all the variadic arguments are passed into function as a list of a given type, why wont compiler automatically unfold lists, or mixture of strings/lists of strings, into a larger ..vars list? (same with append, why not unfold list to elements automatically, etc.). In Fortran, where variadic arguments are used since time immemorial, thats exactly what would happen. Is there a way to have it with Go?






Ali Ali

unread,
Jul 13, 2012, 2:34:41 PM7/13/12
to golan...@googlegroups.com
oops. Correction: By "list" I mean, of course, "slice".

Francisco Souza

unread,
Jul 13, 2012, 2:42:22 PM7/13/12
to Ali Ali, golan...@googlegroups.com
On Fri, Jul 13, 2012 at 3:33 PM, Ali Ali <alj...@gmail.com> wrote:
Hi Go-Experts,

I've got tqo questions, somewhat similar. First, documentation of the append() builtin  (if i unserstand it right) lists the  that the two following constructs are possible.

slice = append(slice, elem1, elem2)
slice = append(slice, anotherSlice...)

However, the second one doesnt seem to work in go-1? The following code does not compile:

 list1:=[]string{"1","2","3"}
 list2:=[]string{"6","7","8"}
 list1=append(list1,list2)

You missed "...":

list1 = append(list1, list2...) 

Another question -- can I mix normal and variadic arguments, like, 

func Check(s string, vars ...string) ( err bool) {
  if s == "one" {
        fmt.Printf("the %s has %d elements\n", s, len(vars) )
        return true
  }
  fmt.Printf("not the one, %v \n", vars)
}

...

ok = Check("one", list2)

This wont compile either: "cannot use list1 (type []string) as type string in function argument"

Again, missing "...":

Check("one", list2...)

--
-fss

Ali Ali

unread,
Jul 13, 2012, 3:01:29 PM7/13/12
to golan...@googlegroups.com, Ali Ali
Dear Francisco,

Thanks for the quick reply!  Its good that it is my missing things rather than Go problems.
The append() question and the function as it was, it works now.

Then I tried to mix it a bit stronger: if I try to have both string and ...var in call, but only ...var in declaration:

func Check(  vars ...string) ( err bool) {
  if vars[0] == "one" {
        fmt.Printf("the %s has %d elements\n", vars[0],  len(vars) )

        return true
  }
  fmt.Printf("not the one, %v \n", vars)
  return true
}

and then calling it as

 _ = Check("nope", list1...)
 _ = Check("one", list2...)

It wont build again, saying "too many arguments in call to Check". But shouldnt the first argument become vars[0] with variadic declaration?




On Friday, July 13, 2012 1:42:22 PM UTC-5, Francisco Souza wrote:

André Moraes

unread,
Jul 13, 2012, 3:21:37 PM7/13/12
to Ali Ali, golan...@googlegroups.com

Check("one", list2...)
 
You defined Check to expect a list of strings and you are passing one string and a list of strings.

This works:

=========
package main

import "fmt"

func do(val ...string) {
for _, v := range val {
println(v)
}
}

func main() {
fmt.Println("Hello, playground")
tmp := []string{"abc","123"}
//do("one", "two", tmp...) // wrong
other := append([]string{"one", "two"}, tmp...)
do(other...)
}

andrey mirtchovski

unread,
Jul 13, 2012, 3:22:08 PM7/13/12
to Ali Ali, golan...@googlegroups.com
> It wont build again, saying "too many arguments in call to Check". But
> shouldnt the first argument become vars[0] with variadic declaration?

the language specification 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 .... In this case no new
slice is created." [1]

in your case you're passing both T and []T. go will create a new []T
only in the absence of []T as the last argument to the variadic
function and therefore complains that it's seeing more than the []T it
expected. this means for your rewritten Check(vars ...string) you must
either do:

Check("one", "1", "2", "3")

or

Check([]string{"one", "1", "2", "3"})

but not a mix of the two.

--
1: http://golang.org/ref/spec#Passing_arguments_to_..._parameters

andrey mirtchovski

unread,
Jul 13, 2012, 3:25:33 PM7/13/12
to Ali Ali, golan...@googlegroups.com
> Check([]string{"one", "1", "2", "3"})

make that Check([]string{"one", "1", "2", "3"}...), sorry.

Ali Ali

unread,
Jul 13, 2012, 3:43:55 PM7/13/12
to golan...@googlegroups.com


On Friday, July 13, 2012 2:21:37 PM UTC-5, André Moraes wrote:

Check("one", list2...)
 
You defined Check to expect a list of strings and you are passing one string and a list of strings.


The point is, shouldn't it be the same thing? I defined Check to expect a (single) variadic list of strings. If arguments are defined to be variadic, then woul'nt it be natural to expect that  (a, b, c, d) , ([a,b], c,d), (a, [b,c], d) and ( a, [b,c,d]) are all equivalent to each other?
 
This works:

This works for sure,thanks.

Kyle Lemons

unread,
Jul 13, 2012, 5:19:52 PM7/13/12
to Ali Ali, golan...@googlegroups.com
It might be comparable, but it would hide the performance penalty of allowing that, and it would make it possible for a function to change signature and silently start failing (like if Check used to have a first param that was special and then a list and the first was removed).  When you have a ...arg, the compiler will bottle the parameters up in a slice and pass that as a parameter.  When the ... is used on the passing side, it re-uses the slice, so it can be a performance gain.  It is no longer clear whether this gain is applicable or not if using ... can also require reallocating and appending.  There are also slightly different semantics, but I won't get into that as it's somewhat nuanced.

Rémy Oudompheng

unread,
Jul 13, 2012, 5:42:31 PM7/13/12
to Ali Ali, golan...@googlegroups.com
If the function has type func (...interface{}), it's not natural to expect that
f(a, []int{b,c}, d) is the same as f(a, b, c, d).

Rémy.
Reply all
Reply to author
Forward
0 new messages