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 cases 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, 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 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 proceed further. - Is the above code legal with the current design but because the compiler has not implemented it yet? - Any ideas on how could the current design be able to produce something even simpler? - If it is impossible to archive a similar implementation, what could be the best practices to implement a generic clamp function? 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/073b7b40-7505-49ae-963d-83441b9d766dn%40googlegroups.com.