Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Variadic func changes []byte(s) cap #24972

Closed
inancgumus opened this issue Apr 20, 2018 · 7 comments
Closed

Variadic func changes []byte(s) cap #24972

inancgumus opened this issue Apr 20, 2018 · 7 comments

Comments

@inancgumus
Copy link
Contributor

What version of Go are you using (go version)?

Go 1.10.1

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

darwin/amd64

What did you do?

When you call a variadic func with a byte slice, calling cap is creating different results.

x := []byte("a")
    
// without this, Println prints 32 32
func(a ...[]byte) {}(x)
	
fmt.Println(cap(x), cap([]byte("a"))) // 8 32

https://play.golang.org/p/ZcrsUNAbPZr

What did you expect to see?

32 32

What did you see instead?

8 32

@bradfitz
Copy link
Contributor

This is an implementation detail. You're seeing differences in how the compiler chooses to implement things.

The language doesn't guarantee the the capacity on a conversion from a string.

See #24163 and #24204.

For now, if the capacity is important for your application, use make and set the capacity explicitly.

@inancgumus
Copy link
Contributor Author

Thanks @bradfitz I just found it and wanted to let you know. It's not that I was using this in my application, I was just experimenting with it because of curiosity.

Do you know which part of the implementation changes the cap of the passed [][]byte?

@randall77
Copy link
Contributor

If the backing array for the slice is allocated on the heap, it gets its capacity by rounding up to the next object size, in this case 8.
If the backing array for the slice is allocated on the stack, it gets its capacity from the temporary buffer we allocate on the stack, which has capacity 32.
So the difference in your two cases is whether escape analysis decides to allocate the backing array on the heap or the stack.
See src/runtime/string.go:stringtoslicebyte and friends.

@inancgumus
Copy link
Contributor Author

inancgumus commented Apr 21, 2018

@randall77 That's great, you've explained all in detail! I was looking for its assembly output and I was suspecting of stringtoslicebyte, tmpBuf, and rawbyteslice etc. Thanks for validating it!

@inancgumus
Copy link
Contributor Author

For clarity, I think that the spec might say something about this: "Capacity of a slice is implementation specific when it's not specified explicitly by a make call.".

@bradfitz
Copy link
Contributor

@inancgumus, that's what #24163 is about.

@inancgumus
Copy link
Contributor Author

Ah OK, sorry, I read the whole conversation now. Thank you.

@golang golang locked and limited conversation to collaborators Apr 22, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants