Tried writing a poor man's union (sum) "type" using generic functions and recursion but found an issue. Here's the code:
type nothing any
type Or[V, R any] struct {
value any
rest any
}
func NewOr[V any]() Or[V, nothing] {
return Or[V, nothing]{nil, nil}
}
func TypeOr[V, W, R any](or Or[W, R]) Or[V, Or[W, R]] {
return Or[V, Or[W, R]]{nil, or}
}
type ErrorA struct {}
type ErrorB struct {}
type ErrorC struct {}
var UseCaseError = TypeOr[ErrorA](TypeOr[ErrorB](NewOr[ErrorC]()))
So far so good. If you copy and paste the above code into VSCode you can see a readable type in the tooltip for the UseCaseError variable.
To get the value from this variable we need a function like this:
func Get[V, W, R any](or Or[W, R]) (*V, bool) {
if value, ok := or.value.(V); ok {
return &value, true
}
// Here the compiler should check whether the type parameter R
// is actually a type Or[W1, R1].
// If it is the compiler should infer W1, R1 and insert the code from the 1st branch.
// Otherwise it should insert the code from the 2nd branch.
if_at_compile_time isOr := R.(Or[W1, R1 infer]); isOr {
return Get[V](or.rest.(Or[W1, R1]))
} else {
return (nil, false)
}
}
Without compile-time check like this there's no way to break from the recursion inside a generic function (I think). But it looks like there's nothing like this in Go? Perhaps there should be?