Home > Software engineering >  generics: constraint to a type with a function returning itself
generics: constraint to a type with a function returning itself

Time:04-09

Is it possible to write a generic type constraint so that the type contains a function returning the same type or is it the same problem as with normal interfaces? Example use-case would be a builder with chainable methods.

Let's say I have a builder IntFoo which has a SetFoo method responsible for setting the foo field to some value. Playground link

type IntFoo struct {
    foo int
}

func (me *IntFoo) SetFoo(foo int) *IntFoo {
    me.foo = foo
    return me
}

Now I might have several builders like this one with different types and I'd like to define a constraint like this:

type Builder[F any] interface {
    SetFoo(F) Builder[F] // this return type is problematic
}

and some function consuming the Builder-constrained type like so:

// some generic demo function
func demo[E Builder[F], F any](builder E, foo F) {
    builder.SetFoo(foo)
    return
}

Trying to call the demo function

    e := &IntFoo{}
    demo(e, 2)

results in an error:

[compiler InvalidTypeArg] [E] *IntFoo does not implement Builder[int] (wrong type for method SetFoo)
        have SetFoo(foo int) *IntFoo
        want SetFoo(int) Builder[int]

CodePudding user response:

You want to return the original type, not the interface you define for the method. So this will work:

type Builder[F any, E any] interface {
    SetFoo(F) E
}

and reworking demo slightly:

func demo[F any, E Builder[F, E]](builder E, foo F) E {
    return builder.SetFoo(foo)
}

https://go.dev/play/p/jkD9xTUDbjV

result := demo(e, 2)
fmt.Printf("%[1]T : %[1]v\n", result) // *main.IntFoo : &{2}
  • Related