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.

Reply via email to