I guess thinking about some more, I don't really understand the point of
what you're doing. It seems you *can* actually get the static guarantee you
want - you just have to spell the call
`(*C.mystruct)(UnsafePointerOrError(s))` instead of
`PointerOrError[C.mystruct](s)`. If you *could* restrict the type parameter
to be "any pointer", the two would actually be entirely equivalent, giving
you exactly the same guarantees.

I think in reality you *don't* want to allow "any pointer type". I think in
reality you want the type to be dependent on the C++ function you are
calling - which returns the Status. I don't think you can use templated C++
types, otherwise you would probably want to do something like
func Call[T any](f func(…) C.StatusOr<T>) (T, error)

In the absence of that, you might try listing the types which are valid:
type CPointer interface{
    *C.MyStruct | *C.MyOtherStruct | *C.YourStruct
}
func PointerOrError[T CPointer](s C.StatusOr) (T, error) { … }



On Sat, Apr 15, 2023 at 10:24 PM Axel Wagner <axel.wagner...@googlemail.com>
wrote:

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

Reply via email to