Create instance of generic type with pointer to type parameter

Issue

Given these type definitions:

type N interface{ ~int | ~float32 | ~float64 }

type S[T any] struct {
    t T
}

type myInt int

type pSpMyInt[T myInt] *S[*T]
type spMyInt[T *myInt,] S[T]
type spMyInt2[T myInt] S[*T]

I can create a var of type pSpMyInt with

func createPS[T myInt]() pSpMyInt[T] {
    var i T
    s := S[*T]{t: &i}
    return &s
}

But I can not figure out how to create vars of spMyInt or spMyInt2.

This

func createSP[T myInt]() spMyInt2[T] {
    var i T
    s := S[*T]{t: &i}
    return s
}

fails to compile
cannot use s (variable of type S[*T]) as type spMyInt2[T] in return statement.

Solution

First of all, do NOT use exact type parameter constraints. It almost never makes sense. When you declare a function as createPS[T myInt](), the type parameter type set has cardinality 1, so it can effectively be instantiated only and ever by myInt. You could rewrite the function like the following just as fine:

func createPS() pSpMyInt[myInt] {
    var i myInt
    s := S[*myInt]{t: &i}
    return &s
}

With that out of the way:

The type S[*T] is just not the same as spMyInt2[T]. However, since spMyInt2[T]‘s underlying type is S[*T], you can simply convert:

func createSP2[T myInt]() spMyInt2[T] {
    var i T
    s := S[*T]{t: &i}
    return spMyInt2[T](s) // conversion
}

As for type spMyInt[T *myInt,] S[T] (where the comma is not a typo but is needed to avoid a parsing ambiguity), the thing isn’t that simple.

The problem is that a type parameter is not its type constraint. Therefore type literals can’t be used to instantiate different unnamed type literals. To be clear:

// naive attempt that doesn't compile
func createSP1[T myInt]() spMyInt[*T] {
    var i T
    s := S[*T]{t: &i}
    return spMyInt[*T](s)
}

You might think that spMyInt[T *myInt] has a type parameter constrained to *myInt and the function T is constrained by the base type myInt, therefore *T should satisfy T *myInt. This is not correct for the apparently unobvious reason that the type literal *T is not equivalent to *myInt. So actually you can’t write a generic constructor for type spMyInt[T *myInt,] S[T].

However you are in luck because the type constraint had cardinality one. So you can just remove the type parameter:

func createSP1() spMyInt[*myInt] {
    var i myInt
    s := S[*myInt]{t: &i}
    return spMyInt[*myInt](s)
}

Answered By – blackgreen

Answer Checked By – Terry (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.