Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go/types: Type mismatch when using interfaces and generics in Go #61771

Closed
ruiborda opened this issue Aug 4, 2023 · 2 comments
Closed

go/types: Type mismatch when using interfaces and generics in Go #61771

ruiborda opened this issue Aug 4, 2023 · 2 comments

Comments

@ruiborda
Copy link

ruiborda commented Aug 4, 2023

I'm using
go version go1.20.7 linux/amd64
The following code is supposed to be the same but they are not the same.

func OrderBySeqNum[S Sequenced](items []S) []S {
	return items
}
func OrderBySeqNum[S []Sequenced](items S) S {
        return items
}

This code works.

package main

import (
	"fmt"
)

type Person struct {
	ID     uint
	SeqNum uint8
}

func (p Person) GetSeqNum() uint8 {
	return p.SeqNum
}

type Persons []Person

type Animal struct {
	ID     uint
	SeqNum uint8
}

func (a Animal) GetSeqNum() uint8 {
	return a.SeqNum
}

type Animals []Animal

type Sequenced interface {
	GetSeqNum() uint8
}

func OrderBySeqNum[S Sequenced](items []S) []S {
	for i := 0; i < len(items); i++ {
		for j := 0; j < len(items)-i-1; j++ {
			if items[j].GetSeqNum() > items[j+1].GetSeqNum() {
				items[j], items[j+1] = items[j+1], items[j]
			}
		}
	}
	return items
}

func main() {
	persons := Persons{
		Person{
			ID:     1,
			SeqNum: 2,
		},
		Person{
			ID:     2,
			SeqNum: 3,
		},
		Person{
			ID:     3,
			SeqNum: 1,
		},
	}
	animals := Animals{
		Animal{
			ID:     1,
			SeqNum: 2,
		},
		Animal{
			ID:     2,
			SeqNum: 3,
		},
		Animal{
			ID:     3,
			SeqNum: 1,
		},
	}

	fmt.Println(OrderBySeqNum(persons))
	fmt.Println(OrderBySeqNum(animals))
}

This code doesn't work.

package main

import (
	"fmt"
)

type Person struct {
	ID     uint
	SeqNum uint8
}

func (p Person) GetSeqNum() uint8 {
	return p.SeqNum
}

type Persons []Person

type Animal struct {
	ID     uint
	SeqNum uint8
}

func (a Animal) GetSeqNum() uint8 {
	return a.SeqNum
}

type Animals []Animal

type Sequenced interface {
	GetSeqNum() uint8
}

func OrderBySeqNum[S []Sequenced](items S) S {
	for i := 0; i < len(items); i++ {
		for j := 0; j < len(items)-i-1; j++ {
			if items[j].GetSeqNum() > items[j+1].GetSeqNum() {
				items[j], items[j+1] = items[j+1], items[j]
			}
		}
	}
	return items
}

func main() {
	persons := Persons{
		Person{
			ID:     1,
			SeqNum: 2,
		},
		Person{
			ID:     2,
			SeqNum: 3,
		},
		Person{
			ID:     3,
			SeqNum: 1,
		},
	}
	animals := Animals{
		Animal{
			ID:     1,
			SeqNum: 2,
		},
		Animal{
			ID:     2,
			SeqNum: 3,
		},
		Animal{
			ID:     3,
			SeqNum: 1,
		},
	}

	fmt.Println(OrderBySeqNum(persons))
	fmt.Println(OrderBySeqNum(animals))
}

What I want to achieve is to do something like this:

package main

import (
	"fmt"
)

type Person struct {
	ID     uint
	SeqNum uint8
}

func (p Person) GetSeqNum() uint8 {
	return p.SeqNum
}

type Persons []Person

type Animal struct {
	ID     uint
	SeqNum uint8
}

func (a Animal) GetSeqNum() uint8 {
	return a.SeqNum
}

type Animals []Animal

type Sequenced interface {
	GetSeqNum() uint8
}

// I add this line to have many possibilities.
type Sequenceds []Sequenced

func OrderBySeqNum[S Sequenceds](items S) S {
	for i := 0; i < len(items); i++ {
		for j := 0; j < len(items)-i-1; j++ {
			if items[j].GetSeqNum() > items[j+1].GetSeqNum() {
				items[j], items[j+1] = items[j+1], items[j]
			}
		}
	}
	return items
}

func main() {
	persons := Persons{
		Person{
			ID:     1,
			SeqNum: 2,
		},
		Person{
			ID:     2,
			SeqNum: 3,
		},
		Person{
			ID:     3,
			SeqNum: 1,
		},
	}
	animals := Animals{
		Animal{
			ID:     1,
			SeqNum: 2,
		},
		Animal{
			ID:     2,
			SeqNum: 3,
		},
		Animal{
			ID:     3,
			SeqNum: 1,
		},
	}

	fmt.Println(OrderBySeqNum(persons))
	fmt.Println(OrderBySeqNum(animals))
}
@ruiborda ruiborda changed the title affected/package: Type mismatch when using interfaces and generics in Go go/types: Type mismatch when using interfaces and generics in Go Aug 4, 2023
@ianlancetaylor
Copy link
Contributor

A slice of an interface type is not the same as a slice of a type that is constrained by that interface. In the version that doesn't compile, you have

type Sequenced interface {
	GetSeqNum() uint8
}

func OrderBySeqNum[S []Sequenced](items S) S {
    ...
}

    OrderBySeqNum(persons)

The type of persons is not a slice of an interface type, so it doesn't satisfy the constraint []Sequenced. It's true that the type of the element type of the persons slice satisfies the constraint Sequenced, but that is not the same thing.

@ianlancetaylor ianlancetaylor closed this as not planned Won't fix, can't repro, duplicate, stale Aug 4, 2023
@ruiborda
Copy link
Author

ruiborda commented Aug 5, 2023

I reopen the issue. In the following example, you can convert the types, however, in the code I provided where it fails, you cannot convert

        type typeA uint8 
	type typeBEqualsTypeA uint8 
	
	var a typeA = 1
	var b typeBEqualsTypeA 
	
	a= typeA(b)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants