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/CAP%2BmWpJO3xE4Wwg22cXAeY-JKFxk%3D3uneOTEKwLrWjcqLt_Y9A%40mail.gmail.com.

Reply via email to