Navigation Menu

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/go2go: invalid unsafe.Sizeof operation on parametric type #43208

Closed
dsnet opened this issue Dec 16, 2020 · 7 comments
Closed

cmd/go2go: invalid unsafe.Sizeof operation on parametric type #43208

dsnet opened this issue Dec 16, 2020 · 7 comments

Comments

@dsnet
Copy link
Member

dsnet commented Dec 16, 2020

Consider this snippet:

func SizeOf[T any]() int {
	var t T
	return unsafe.Sizeof(t)
}

Compiling this currently errors with:

prog.go2:10:9: invalid operation: unsafe.Sizeof undefined for t (variable of type parameter type T)

I may be a bit behind on the latest with the generics proposal, but it seems to me that unsafe.Sizeof should work for parametric types.

\cc @griesemer

@ianlancetaylor
Copy link
Contributor

It's a complex issue because unsafe.Sizeof is defined to return a compile-time constant. That implies that it's OK to write [unsafe.Sizeof(T)]byte. And that carries some complex implications for the implementation. So at least for now I think we do not permit unsafe.Sizeof on generic types.

@ianlancetaylor
Copy link
Contributor

Because I don't think this is an issue with cmd/go2go, I'm going to close this issue. This is something to bring up during or after the discussion of the generics proposal itself.

@dsnet
Copy link
Member Author

dsnet commented Dec 18, 2020

Thanks @ianlancetaylor for the explanation. FYI, my use case for this was that I was trying to write a generic function to obtain the exact index of a pointer to an element in a slice:

// IndexPointer returns the index of the element in s that is exactly identical to p,
// or -1 if p is not present in s.
func IndexPointer[T any](s []T, p *T) int {
	if len(s) == 0 || p == nil {
		return -1
	}
	if &s[0] == p {
		return 0 // handles the special case where unsafe.Sizeof(T) is zero
	}
	var t T
	offset := uintptr(unsafe.Pointer(p)) - uintptr(unsafe.Pointer(&s[0]))
	index := offset / unsafe.Sizeof(t)
	if index < uintptr(len(s)) && &s[index] == p {
		return int(index)
	}
	return -1
}

Without the use of unsafe, I don't believe there is a way to do the above in O(1), the best in O(n):

func IndexPointer[T any](s []T, p *T) int {
	for i := range s {
		if &s[i] == p {
			return i
		}
	}
	return -1
}

There have been several times where I needed an operation like this, and it would be nice if a standard library function in Go 2 provided it.

@ianlancetaylor
Copy link
Contributor

How about reflect.TypeOf(t).Size()?

@randall77
Copy link
Contributor

randall77 commented Dec 18, 2020 via email

@AndrewWPhillips
Copy link

Possibly a duplicate of #40301

@griesemer
Copy link
Contributor

Yes, this is essentially #40301; thanks @AndrewWPhillips .

@golang golang locked and limited conversation to collaborators Jan 1, 2022
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

6 participants