append(store, obj) not used

2,135 views
Skip to first unread message

Steven Rice

unread,
Sep 14, 2012, 9:59:22 AM9/14/12
to golan...@googlegroups.com
Can anyone explain to me the reason that this error occurs when a function appends?
Example:
package main

func save(obj chan int, store []chan int) {
append(store, obj)
}

func main() {
store := make([]chan int, 0)
obj := make(chan int, 10)
save(obj, store)
}

Ian Lance Taylor

unread,
Sep 14, 2012, 10:04:55 AM9/14/12
to Steven Rice, golan...@googlegroups.com
Since append is a builtin function, you are computing a value that you
don't use. But, you're right, it's safe to ignore the result in this
program. I suggest opening an issue about this for further
discussion.

Ian

Larry Clapp

unread,
Sep 14, 2012, 10:06:55 AM9/14/12
to golan...@googlegroups.com
Append returns a value, in case it has to expand the array backing the slice.  You need to say

store = append(store, obj)

But I think even that is wrong, because I don't think the store from main() is updated.  (But I could be wrong; I'm not clear on the semantics of assigning to a slice.)

Anyway, you might need to say

package main

func save(obj chan int, store *[]chan int) {
*store = append(*store, obj)
}

func main() {
store := make([]chan int, 0)
obj := make(chan int, 10)
save(obj, &store)
}

-- L

Jan Mercl

unread,
Sep 14, 2012, 10:07:05 AM9/14/12
to Steven Rice, golan...@googlegroups.com
On Fri, Sep 14, 2012 at 3:59 PM, Steven Rice <stevenw...@gmail.com> wrote:
> Can anyone explain to me the reason that this error occurs when a function
> appends?

As the error says: you're appending something to something other, then
throwing the hard earned result away. You probably want this scheme:

theResult = append(theSlice, aValue)

-j

Jan Mercl

unread,
Sep 14, 2012, 10:17:26 AM9/14/12
to Ian Lance Taylor, Steven Rice, golan...@googlegroups.com
On Fri, Sep 14, 2012 at 4:04 PM, Ian Lance Taylor <ia...@google.com> wrote:
> Since append is a builtin function, you are computing a value that you
> don't use. But, you're right, it's safe to ignore the result in this
> program. I suggest opening an issue about this for further
> discussion.

Please pardon my ignorance, but I wonder why it is safe 'in this
program' and what the issue matter would/should be about?

-j

Steven Rice

unread,
Sep 14, 2012, 10:19:16 AM9/14/12
to golan...@googlegroups.com
Thanks guys, now I feel like I was being lazy because I should have known that. I had the language spec right in front of me.

Jesse McNelis

unread,
Sep 14, 2012, 10:19:15 AM9/14/12
to Larry Clapp, golan...@googlegroups.com
On Sat, Sep 15, 2012 at 12:06 AM, Larry Clapp <la...@theclapp.org> wrote:
> Append returns a value, in case it has to expand the array backing the
> slice. You need to say
>
> store = append(store, obj)
>
> But I think even that is wrong, because I don't think the store from main()
> is updated. (But I could be wrong; I'm not clear on the semantics of
> assigning to a slice.)

slices are just like every other value in Go, nothing magical about them.


> Anyway, you might need to say
>
> package main
>
> func save(obj chan int, store *[]chan int) {
> *store = append(*store, obj)
> }
>
> func main() {
> store := make([]chan int, 0)
> obj := make(chan int, 10)
> save(obj, &store)
> }

Since append() can allocate a new underlying array from the store
slice, you do need some way of communicating this change up the stack.
You can either do this by updating a pointer(as is the example above)
or you can have your function return the value.
Ignoring the value isn't an option.

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

Ian Lance Taylor

unread,
Sep 14, 2012, 10:35:26 AM9/14/12
to Jan Mercl, Steven Rice, golan...@googlegroups.com
I think it is safe in this particular program because there is always
for the second slice in the capacity of the first slice. In this case
append should always return the first argument. The spec seems to say
that the allocation will occur only in the case that the capacity is
not large enough. It is possible for the program to know that the
capacity is always large enough, and in that case it seems safe to
ignore the result of append.

Of course good programming practice would be to always use the result
of append, and it may be that there is nothing that should be changed
here.

Ian

Jan Mercl

unread,
Sep 14, 2012, 10:46:14 AM9/14/12
to Ian Lance Taylor, Steven Rice, golan...@googlegroups.com
On Fri, Sep 14, 2012 at 4:35 PM, Ian Lance Taylor <ia...@google.com> wrote:

> I think it is safe in this particular program because there is always
> for the second slice in the capacity of the first slice. In this case
> append should always return the first argument.

I don't think so. Because slices are value types, I think it's never
okay to ignore the append's result, cap enough or not:
http://play.golang.org/p/x73ctDQDR_

-j

Jesse McNelis

unread,
Sep 14, 2012, 10:48:19 AM9/14/12
to Ian Lance Taylor, Jan Mercl, Steven Rice, golan...@googlegroups.com
On Sat, Sep 15, 2012 at 12:35 AM, Ian Lance Taylor <ia...@google.com> wrote:
> I think it is safe in this particular program because there is always
> for the second slice in the capacity of the first slice.

Look again, they are appending a channel with a cap of ten to a slice
with a cap of zero.
store := make([]chan int, 0)
obj := make(chan int, 10)


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

Jan Mercl

unread,
Sep 14, 2012, 10:52:36 AM9/14/12
to Jesse McNelis, Steven Rice, Ian Lance Taylor, golan...@googlegroups.com

Even a big enough capacity doesn't help to make it safe to ignore the result

-j

Larry Clapp

unread,
Sep 14, 2012, 11:07:20 AM9/14/12
to golan...@googlegroups.com, Ian Lance Taylor, Steven Rice

Funky. 

Jesse McNelis

unread,
Sep 14, 2012, 11:13:56 AM9/14/12
to Larry Clapp, golan...@googlegroups.com, Ian Lance Taylor, Steven Rice
On Sat, Sep 15, 2012 at 1:07 AM, Larry Clapp <la...@theclapp.org> wrote:
> And yet consider http://play.golang.org/p/Px1g-_R3qG

http://play.golang.org/p/DQsU36EQsb
Yep, the len of the original slices stay the same until you change them.


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

Jan Mercl

unread,
Sep 14, 2012, 11:22:18 AM9/14/12
to Larry Clapp, Steven Rice, Ian Lance Taylor, golan...@googlegroups.com

Carefully reread the relevant specs part. If the cap is known to be enough then it *is* safe to throw away the append's result as long as the real len is kept elsewhere or inferred etc. and the slice is eventually re-sliced. My apologies, Ian, you were right.

-j

Kyle Lemons

unread,
Sep 14, 2012, 2:04:15 PM9/14/12
to Ian Lance Taylor, Jan Mercl, Steven Rice, golan...@googlegroups.com
One possibility (I can't tell if being more permissive would break the Go1 promises or not) would be to treat 

slice = append(slice, val)

as it currently exists, but make the code generated for

append(slice, val)

panic if it would have reallocated slice.  This seems like it might allow the programmer to hint things to the compiler that would improve performance without hiding errors? 

Ingo Oeser

unread,
Sep 14, 2012, 4:39:20 PM9/14/12
to golan...@googlegroups.com
This just turns a source of errors we can catch (and do catch) at compile time into a runtime error for the win of a obscure special case. Is it really worth it?

Dan Kortschak

unread,
Sep 14, 2012, 5:31:22 PM9/14/12
to Jesse McNelis, Larry Clapp, golan...@googlegroups.com, Ian Lance Taylor, Steven Rice
Slightly offtopic, but I noticed while playing around with that that if the start of the slice range is out of range (this is only possible if it's negative so this is not a very significant thing) the compiler complains that the constant overflows uint64. Since slice indices are int, why is this type referred to?

Matt Kane's Brain

unread,
Sep 14, 2012, 6:12:42 PM9/14/12
to Jan Mercl, Larry Clapp, Steven Rice, Ian Lance Taylor, golan...@googlegroups.com
It's still wrong. This will print an empty slice for a.

func main() {
a := make([]int, 0, 6)
b := append(a, 6)
fmt.Println(a, b)
}

runtime·appendslice in src/pkg/runtime/slice.c never alters the slice
header for a, even though the underlying array has likely been
altered.
> --
>
>



--
matt kane's brain
http://hydrogenproject.com

andrey mirtchovski

unread,
Sep 14, 2012, 7:28:10 PM9/14/12
to Dan Kortschak, Jesse McNelis, Larry Clapp, golan...@googlegroups.com, Ian Lance Taylor, Steven Rice
On Fri, Sep 14, 2012 at 3:31 PM, Dan Kortschak
<dan.ko...@adelaide.edu.au> wrote:
> Slightly offtopic, but I noticed while playing around with that that if the start of the slice range is out of range (this is only possible if it's negative so this is not a very significant thing) the compiler complains that the constant overflows uint64. Since slice indices are int, why is this type referred to?

src/cmd/gc/walk.c:2489 and the lines below have some clues, although
it's hard for me to unravel the whole sequence (how it passes the
check for int earlier, or why it does a check for uintptr if an
argument to a function).
Reply all
Reply to author
Forward
0 new messages