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

cmd/compile: len(T{}) syntax for generic bytes #69100

Closed
karalabe opened this issue Aug 28, 2024 · 4 comments
Closed

cmd/compile: len(T{}) syntax for generic bytes #69100

karalabe opened this issue Aug 28, 2024 · 4 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime.

Comments

@karalabe
Copy link
Contributor

karalabe commented Aug 28, 2024

Go version

go version go1.22.6 darwin/arm64

Output of go env in your module/workspace:

-

What did you do?

https://go.dev/play/p/1awTlRO9FrO

package main

func f[T interface{ ~[2]int | ~[4]int }]() {
	println(len(T{}))     // Zero alloc, build failure
	println(len(*new(T))) // Build ok, but allocates
}

func main() {
	f[[2]int]()
}

What did you see happen?

Only the version that allocates runtime works. The Go compiler has a nifty optimization for doing len([2]byte) for example to evaluate it during compile time, but it doesn't seem to work for genetic types. I can allocate it in the generic version, but then I pay for a useless alloc and GC cost.

What did you expect to see?

I expect a 0 alloc way to figure out the length of the array.


Edit: For the reference, my use case is having a generic encoder that can encode a bunch of different static sized byte slices (e.g. maybe 10 different sizes). The input is provided as a pointer to a slice (I have non pointer too, but this one needs a pointer). A nil pointer would encode as a static sized byte array of all zeroes, hence why I need to know what size it would be without allocating since my lib is zero alloc (for now :P).

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Aug 28, 2024
@golang golang deleted a comment Aug 28, 2024
@ianlancetaylor
Copy link
Member

That is how the language works. See https://go.dev/ref/spec#Length_and_capacity. Calling len on a type parameter does not produce a constant.

This is impossible to fix because of how constants and generics work in Go. The only way to make it work would be to require any generic function that calls len to be compiled separately for each possible type argument. We aren't going to make that choice. Sorry.

@ianlancetaylor ianlancetaylor closed this as not planned Won't fix, can't repro, duplicate, stale Aug 28, 2024
@karalabe
Copy link
Contributor Author

Im also happy to be able to compute the length of a type parameter without instantiating one. Any idea how to do that? Whilst I can accept that the len(T{}) compiler trick doesn't work for generics, IMO the use case should be solvable without allocating.

@zigo101
Copy link

zigo101 commented Aug 29, 2024

Now, type composites needs a core type now, but the "new" function doesn't require that: https://go101.org/generics/777-operations-on-values-of-type-parameter-types.html

This probably will be resolved in #63940

@ianlancetaylor
Copy link
Member

You could try

	println(reflect.TypeFor[T]().Len())

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime.
Projects
None yet
Development

No branches or pull requests

4 participants