Home > Back-end >  Type constraint (E) not met by embedding (E) in concrete struct
Type constraint (E) not met by embedding (E) in concrete struct

Time:06-11

I'm trying to implement a variation of the pointer-method example for type-parameters design pattern, in order to abstract over some unified repository interface.

I was under the impression that the Person struct would inherit the method-set of Entity if it composes *Entity, but I get a compile-time error as below. Could someone please explain why the type-constraint is not met and how to fix this code?

Apologies for the awful title; if someone could suggest an improved summary that would be fantastic (I'm quite new to Go).

Thanks :)

package main

// domain

type PEntity[E any] interface {
    *E
    SetID(id string)
}

type Entity struct {
    ID string
}

func (e Entity) SetID(id string) {
    e.ID = id
}

type Repository[E Entity, PE PEntity[E]] interface {
    Get(id string) *E
}

// data

type Person struct {
    *Entity
}

type PersonRepository interface {
    Repository[Person, *Person] // -> Person does not implement Entity
    AddPet(name string)
    // ...
}

CodePudding user response:

The constraint E Entity — syntactic sugar for E interface{ Entity } — effectively means that the type set of E includes exactly one type term Entity, which is a struct.

When you have exact constraints, you can only satisfy them with that very type, so it doesn't make much difference from not having the type parameter at all and declaring regular function arguments. As an example to help you understand:

func Foo[T int](v T) {}

is practically the same as:

func Foo(v int) {}

Therefore you can satisfy the constraint E Entity exclusively with the struct Entity.

Clearly Person is not Entity. Field embedding only affects the method set of the embedding type, which has no bearings on type identity.

If you change the constraint to a method-only (basic) interface — Or or change Entity directly (playground) —, then it will take only the method set into account and successfully compile:

type Repository[E interface{ SetID(id string) }, PE PEntity[E]] interface {
    Get(id string) *E
}

More about basic vs. non-basic interfaces: interface contains type constraints: cannot use interface in conversion

  • Related