New() functions for abstract classes

I am writing some demonstration code that creates a Stack interface and then creates two concrete structures LinkedStack and ArrayStack that implement the interface.

I have a New() function for each concrete type that returns a new instance of each, properly initialized.

I would like to have a function “Union” that takes two Stacks and returns a new Stack containing the contents of both. If I hard-code the Union function to return a LinkedStack, this works fine. I can use my New() function for the LinkedStack, populate it, and return the new instance.

But what I’d -really- like is to create a new instance of whichever Stack type was passed as the first argument. The problem here is figuring out which New() function to call. Is there a way to do this?

Yes, you can switch on the type of the first argument, something like this:

func NewByType(s Stack) Stack {
	switch s.(type) {
	case LinkedStack:
		return NewLinkedStack()
	case ArrayStack:
		return NewArrayStack()
	default:
		panic("Did not expect this type")
	}
}

You could also try reflection, though I’m not sure you can find a func by its name.

Thanks! This doesn’t seem to work in my case, possibly because I’m also using generics:

func Append[S2 Stack[T], S1 Stack[T], T any](s1 S1, s2 S2) S1 {
        var result S1
        switch result.(type) {
                case LinkedStack[T]:
                        result := NewLinked[T]()
                case ArrayStack[T]:
                        result := NewArray[T]()
                default:
                        panic("Unsupported Type")
        }
        return result
}

This gives: cannot use type switch on type parameter value result (variable of type S1 constrained by Stack[T])

func Append[S2 Stack[T], S1 Stack[T], T any](s1 S1, s2 S2) S1 {
	var result S1
	switch any(result).(type) {
	case LinkedStack[T]:
		result := NewLinked[T]()
	case ArrayStack[T]:
		result := NewArray[T]()
	default:
		panic("Unsupported Type")
	}
	return result
}

Thanks! The any() trick is neat. Still gives me errors, though:

stack/stack.go:127:13: cannot use NewLinked[T]() (value of type LinkedStack[T]) as S1 value in assignment
stack/stack.go:129:13: cannot use NewArray[T]() (value of type ArrayStack[T]) as S1 value in assignment

Why don’t you try to draw inferences?

func Append[S2 Stack[T], S1 Stack[T], T any](s1 S1, s2 S2) S1 {
	var result S1
	switch any(result).(type) {
	case LinkedStack[T]:
		result = any(NewLinked[T]()).(S1)
	case ArrayStack[T]:
		result = any(NewArray[T]()).(S1)
	default:
		panic("Unsupported Type")
	}
	return result
}
1 Like

Amazing! Thank you so much!

(Also – this taught me an amazing amount about how type inference and generics work in Go. I’m still going to need to digest it a bit, but I really, really appreciate your help!)