Re-factoring your example to use CGO, in a small main.go file: ``` $ go run . ./main.go:28:10: cannot use incomplete (or unallocatable) type as a type argument: main._Ctype_struct_MyThing $ cat main.go package main
// struct MyThing; // typedef struct MyThing MyThing; import "C" import ( "fmt" "unsafe" ) import "flag" func PointerOrError[T *Q, Q any](s int) (t T, err error) { var ptr unsafe.Pointer ptr, err = UnsafePointerOrError(s) // <-- unsafe.Pointer, error if err != nil { return } t = (T)(ptr) return } func UnsafePointerOrError(v int) (unsafe.Pointer, error) { return unsafe.Pointer(&v), nil } func main() { flag.Parse() t, _ := PointerOrError[*C.MyThing](1) fmt.Println(t) } ``` On Saturday, April 15, 2023 at 8:41:28 PM UTC+2 Jan wrote: > Thanks! I hadn't realized that one could constraint T to be a pointer type > by using a second type paramater Q, this in nice. > > But alas, it doesn't work. When I copy&pasted your code to mine, and used > an undefined C type ... it complained of the same thing: > > ``` > cannot use incomplete (or unallocatable) type as a type argument: > gomlx/xla._Ctype_struct_StableHLOHolder > ``` > > I'm using it in the following snipped of code: > > ``` > func (comp *Computation) ToStableHLO() (*StableHLO, error) { > if comp.IsNil() || comp.firstError != nil { > return nil, errors.Errorf("Computation graph is nil!?") > } > statusOr := C.ConvertComputationToStableHLO(comp.cCompPtr) > cPtr, err := PointerOrError[*C.StableHLOHolder](statusOr) > if err != nil { > return nil, errors.Wrapf(err, "failed conversion in > Computation.ToStableHLO") > } > return NewStableHLO(cPtr), nil > } > ``` > > I suspect it doesn't allow matching Q to an incomplete type > (`C.StableHLOHolder` in this example), same way as my original version :( > > I think your example in playground doesn't capture that -- the playground > doesn't seem to allow CGO code (i tried this > <https://go.dev/play/p/ZM14sQuK8iN?v=gotip.go?download=true>, but it > didn't even try to compile). > > I mean it's not the end of the world, I can always cast it in the next > line ... it's just one of those little things that would be "ergonomically" > very nice if it worked :) > > > > On Saturday, April 15, 2023 at 3:02:14 PM UTC+2 jake...@gmail.com wrote: > >> What About: >> >> func PointerOrError[T *Q, Q any](s C.StatusOr ) (t T, err error) >> >> Seems to compile: https://go.dev/play/p/n4I-XkONj-O?v=gotip >> >> On Saturday, April 15, 2023 at 6:28:39 AM UTC-4 Jan wrote: >> >>> hi, >>> >>> This is a variation for a previous topic >>> <https://groups.google.com/g/golang-nuts/c/h75BwBsz4YA/m/FLBIjgFBBQAJ>, >>> but since there isn't a clear solution, I thought I would ask if anyone can >>> think of a work around. >>> >>> I've been interacting a lot with C++ libraries from Go, and one of the >>> commonly returned types is an abls::StatusOr >>> <https://abseil.io/docs/cpp/guides/status>, for which I created a >>> simple C wrapper that casts the error and value to a `char *` and `void *` >>> respectively (dropping the type information in between C++ and Go). >>> >>> In Go I want to return the type information, so I defined a small >>> generic function: >>> >>> // PointerOrError converts a StatusOr structure to either a pointer to >>> T with the data >>> // or the Status converted to an error message and then freed. >>> func PointerOrError[T any](s C.StatusOr) (*T, error) { >>> ptr, err := UnsafePointerOrError(s) // returns unsafe.Pointer, error >>> if err != nil { >>> return nil, err >>> } >>> return (*T)(ptr), nil >>> } >>> >>> Now this doesn't work for my forward declared C++ types (most of them >>> are just aliases to C++ objects) -- Go complaints with: `cannot use >>> incomplete (or unallocatable) type as a type argument`, because `T` is >>> incomplete indeed. >>> >>> But ... I will never instantiate `T`, I only care about `*T`, which is >>> not incomplete. >>> >>> But there isn't a way to say a generics attribute is a pointer. So if I >>> use the following: >>> >>> func PointerOrError2[T any](s C.StatusOr) (t T, err error) { >>> var ptr unsafe.Pointer >>> ptr, err = UnsafePointerOrError(s) // <-- unsafe.Pointer, error >>> if err != nil { >>> return >>> } >>> t = (T)(ptr) >>> return >>> } >>> >>> And instantiate it with a `PointerOrError2[*MyType](statusOr)` for >>> instance, I get, as expected: >>> >>> cannot convert ptr (variable of type unsafe.Pointer) to type T >>> >>> Any suggestions to make this work ? >>> >>> I could probably craft something using the `reflect` package, but I was >>> hoping for a smart (and likely faster?) generics solution. >>> >>> cheers >>> Jan >>> >>> >>> >>> >>> >>> >>> -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/639d57d5-37da-424b-a137-41a7bca7e821n%40googlegroups.com.