Generics for both primitive data types and structs?

I am writing my data structure: type MyContainer[constraints.Ordered] {… }

Sadly it can take ints, floats, any primitive data type, but not a custom struct that has Less and Equal implemented.

This forces me to choose: either my payload (what I insert in MyContainer) is a primitive data type, or a struct.

Any idea on how I can bypass this ? I want MyContainer to be able to store both (same generic code can be instantiated either for a primitive data type or a custom struct).

Inside MyContainer, I want to be able to add ints, floats, strings (anything in constraints.Ordered). But I also want my same code to work for any struct that implements type MyInterface { Less(MyInterface) bool}

Another issue: I cannot help but notice with weakness of generics, if you instantiate MyContainer with ints, and you want to inserts a float into it, it will not work. Similarly, if you instantiate a MyContainer with MyStructA, then you cannot insert an object of type MyStructB in it, even though MyStructB implements the same interface as MyStructA. Please advice on how to bypass this as well.

1 Like

You can add another layer of indirection: If you define a Comparable[T] interface:

type Comparable[T any] interface {
	Less(T) bool
	Equal(T) bool
}

Then you can implement a ComparablePrimitive[T]:

type ComparablePrimitive[T constraints.Ordered] struct{ Value T }

func ComparablePrimitiveOf[T constraints.Ordered](v T) Comparable[T] {
	return ComparablePrimitive[T]{Value: v}
}

func (a ComparablePrimitive[T]) Less(b T) bool  { return a.Value < b }
func (a ComparablePrimitive[T]) Equal(b T) bool { return a.Value == b }

Then your MyStruct field just needs to be of type Comparable[T]:

type MyStruct[T any] struct {
	Comparable Comparable[T]
}

Go Playground - The Go Programming Language

I’m not sure what you’re going for here. In Go, you cannot compare different types; they have to be the same type. For example, this won’t compile:

package main

import (
	"fmt"
)

func main() {
	f := 0.123 // type: float64
	i := 3 // type: int
	fmt.Println(f < i)
}
./prog.go:10:18: invalid operation: f < i (mismatched types float64 and int)

So even if the language let you have values with type constraints.Ordered, you can’t do something like:

f := 0.123 // type: float64
i := 3 // type: int
values := []constraints.Ordered{f, i}
fmt.Println(values[0] < values[1])

This is not a weakness: It is a strength. The purpose of generics is to disallow the mixing of types. If you want to have a collection of mixed values, use []interface{}.

Can you show what you’re trying to do with your MyStruct? Are you trying to compare ints to floats and those to MyStructA, etc.? If so, how would mixed types like MyStructA{Name: "skillian"} <= MyStructB{MeltingPointK: 4012} evaluate? Maybe generics/constraints.Ordered aren’t what you need.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.