Great to see you playing with generics. I'll leave it up to the experts to reply about whether the compilation problems are bugs.
But I have a suggestion: don't try to define Vec in an interface with a type set. Just use T[] -- looks like it might simplify things. Scott On Tuesday, August 24, 2021 at 12:55:55 AM UTC+2 Changkun Ou wrote: > Hi golang-nuts, > > I am trying out the latest type parameter and type sets design. > The purpose is to implement a Clamp function that works for numbers and > vectors. > > The version for numbers is straightforward and easy: > > ```go > // Number is a type set of numbers. > type Number interface { > ~int | ~int8 | ~int32 | ~int64 | ~float32 | ~float64 > } > > // Clamp clamps a given value in [min, max]. > func Clamp[N Number](n, min, max N) N { > if n < min { return min } > if n > max { return max } > return n > } > ``` > > Everything is good so far. Then, let's define vector types: > > ```go > // Vec2 represents a 2D vector (x, y). > type Vec2[N Number] struct { > X, Y N > } > > // Vec3 represents a 3D vector (x, y, z). > type Vec3[N Number] struct { > X, Y, Z N > } > > // Vec4 represents homogeneous coordinates (x, y, z, w) that defines > // either a point (W=1) or a vector (W=0). Other case of W need to apply > // a perspective division to get the actual coordinates of X, Y, Z. > type Vec4[N Number] struct { > X, Y, Z, W N > } > ``` > > However, in order to declare a type set of all possible vectors, I tried > two possibilities: > > ```go > // Vec is a type set of vectors. > type Vec[N Number] interface { > Vec2[N] | Vec3[N] | Vec4[N] // ERROR: interface cannot have type > parameters > } > ``` > > ```go > type Vec interface { > Vec2[N Number] | Vec3[N Number] | Vec4[N Number] // ERROR: interface > cannot have type parameters > } > ``` > > Let's just enumerates all possibilities for the Vec type set: > > ```go > // Vec is a type set of vectors. > type Vec interface { > Vec2[float32] | Vec3[float32] | Vec4[float32] | > Vec2[float64] | Vec3[float64] | Vec4[float64] > } > ``` > > However, with this definition, it remains very tricky to construct a > generic implementation for a clamp function: > > ```go > // ERROR: this function does not compile > func ClampVec[V Vec, N Number](v V, min, max N) V { > switch (interface{})(v).(type) { > case Vec2[float32]: > return Vec2[float32]{ > Clamp[float32](v.X, min, max), > Clamp[float32](v.Y, min, max), > } > case Vec2[float64]: > return Vec2[float64]{ > Clamp[float64](v.X, min, max), > Clamp[float64](v.Y, min, max), > } > case Vec3[float32]: > return Vec3[float32]{ > Clamp[float32](v.X, min, max), > Clamp[float32](v.Y, min, max), > Clamp[float32](v.Z, min, max), > } > case Vec3[float64]: > return Vec3[float64]{ > Clamp[float64](v.X, min, max), > Clamp[float64](v.Y, min, max), > Clamp[float64](v.Z, min, max), > } > case Vec4[float32]: > return Vec4[float32]{ > Clamp[float32](v.X, min, max), > Clamp[float32](v.Y, min, max), > Clamp[float32](v.Z, min, max), > Clamp[float32](v.W, min, max), > } > case Vec4[float64]: > return Clamp[float64]{ > Clamp[float64](v.X, min, max), > Clamp[float64](v.Y, min, max), > Clamp[float64](v.Z, min, max), > Clamp[float64](v.W, min, max), > } > default: > panic(fmt.Sprintf("unexpected type %T", v)) > } > } > ``` > > I wish I could converge to a version similar like this: > > ```go > func Clamp[N Number](n, min, max N) N { > if n < min { return min } > if n > max { return max } > return n > } > > // ERROR: this functions does not compile > func ClampVec[N Number, V Vec[N]](v V[N], min, max N) V[N] { > switch (interface{})(v).(type) { > case Vec2[N]: // If V is Vec2[N], then return a Vec2[N]. > return Vec2[N]{ > Clamp[N](v.X, min, max), > Clamp[N](v.Y, min, max), > } > case Vec3[N]: // Similar > return Vec3[N]{ > Clamp[N](v.X, min, max), > Clamp[N](v.Y, min, max), > Clamp[N](v.Z, min, max), > } > case Vec4[N]: // Similar > return Vec4[N]{ > Clamp[N](v.X, min, max), > Clamp[N](v.Y, min, max), > Clamp[N](v.Z, min, max), > Clamp[N](v.W, min, max), > } > default: > panic(fmt.Sprintf("unexpected type %T", v)) > } > } > > // caller side: > > Clamp[float32](256, 0, 255) // 255 > Clamp[float64, Vec2[float64]]({1, 2, 3}, 0, 1) // Vec2[float32]{1, 1, 1} > ... > ``` > > I found myself trapped and not able to further proceed. Is the above code > legal > with the current design but just because the compiler has not implemented > it yet? > Any ideas on how could the current design be able to produce something > even simpler? > > Thank you in advance for your read and help. > -- 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/d4aa1117-f6f1-4260-b6c2-72211ac771c0n%40googlegroups.com.