You should be able to instantiate the function using a Pointer. That is,
you can write

func PointerOrError[T any](s C.StatusOr) (t T, err error) {
        var ptr unsafe.Pointer
        ptr, err = UnsafePointerOrError(s) // <-- unsafe.Pointer, error
        if err != nil {
                return
        }
        return *(*T)(unsafe.Pointer(&ptr))
}

func main() {
    var s C.StatusOr
    p := PointerOrError[*C.mystruct](s)
    _ = p
}

It's unfortunate, of course, that this would allow you to instantiate the
function using a non-pointer as well, but it seems that's impossible to
prevent statically? You can catch it dynamically by doing something akin to

if k := reflect.TypeOf(*new(T)).Kind(); k != reflect.Pointer && k !=
reflect.UnsafePointer {
    panic("PointerOrError must be instantiated with pointer type")
}

Obviously, none of this is ideal, but maybe it's the best you can do -
apart from generating code.

On Sat, Apr 15, 2023 at 8:48 PM Jan <pfei...@gmail.com> wrote:

> 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
> <https://groups.google.com/d/msgid/golang-nuts/639d57d5-37da-424b-a137-41a7bca7e821n%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>

-- 
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/CAEkBMfGmp5utKkj6kH87RyYa5M8mQA15jKf6G86vku2_JqXO3w%40mail.gmail.com.

Reply via email to