Skip to content

proposal: spec: apply constraint type inference to generic types #62460

@itsmontoya

Description

@itsmontoya

Author background

  • Experienced Go Engineer, over 8 years experience
  • Rust, C, Zig

Related proposals

  • I am not sure if this idea has been proposed before
  • This idea does not effect error handling
  • This proposal is about generics

Proposal

  • The proposed change is to allow for better type inference when working with generic referencing interfaces
  • This proposal helps anyone who uses generics in a factory or generator pattern. Additionally, anyone writing data structures
  • The purpose of this proposal is to allow for interface types referencing generics type MyInterface[T] interface { *T } to be inferred better
  • The ability to infer types for interfaces targeting a pointer value of a generic type
  • Allow for pointer types of structs to be inferred more easily by Golang generics
  • The change is backward compatible
  • This change does not affect existing features
  • This change is not a performance improvement

Costs

  • This would not affect the learning scale of Go as it's a deeper subject. For more experienced Engineers, it should make generics more simple to work with
  • More work on the compiler to perform stronger inferring
  • gopls would be affected
  • Negligible, but a slight performance cost
  • No runtime cost
  • A use-case for this feature is available here
  • No prototype is available for the implementation of this feature

Example - Current Requirement

package main

import (
	"strconv"
)

func main() {
	c := New[testType]()
	c.Txn(func(txn Txn[testType, *testType]) {
		txn.New(testType{val: "1"})
		txn.Update("0", func(tt testType) (out testType) {
			return
		})
	})
}

func New[T any, U Value[T]]() *Controller[T, U] {
	var c Controller[T, U]
	c.m = make(map[string]T)
	return &c
}

type Controller[T any, U Value[T]] struct {
	idx int
	m   map[string]T
}

func (c *Controller[T, U]) Txn(fn func(Txn[T, U])) {
	var txn Txn[T, U]
	txn.c = c
	fn(txn)
}

type Txn[T any, U Value[T]] struct {
	c *Controller[T, U]
}

func (txn *Txn[T, U]) New(t T) {
	u := U(&t)
	u.SetID(strconv.Itoa(txn.c.idx))
	txn.c.idx++
}

func (txn *Txn[T, U]) Update(key string, fn func(T) T) {
	v, ok := txn.c.m[key]
	if !ok {
		return
	}

	txn.c.m[key] = fn(v)
}

type testType struct {
	id  string
	val string
}

func (t *testType) SetID(id string) {
	t.id = id
}

type Value[T any] interface {
	*T
	SetID(string)
}

Example - Proposal

package main

import (
	"strconv"
)

func main() {
	c := New[testType]()
	c.Txn(func(txn Txn[testType]) {
		txn.New(testType{val: "1"})
		txn.Update("0", func(tt testType) (out testType) {
			return
		})
	})
}

func New[T any, U Value[T]]() *Controller[T, U] {
	var c Controller[T, U]
	c.m = make(map[string]T)
	return &c
}

type Controller[T any, U Value[T]] struct {
	idx int
	m   map[string]T
}

func (c *Controller[T, U]) Txn(fn func(Txn[T, U])) {
	var txn Txn[T, U]
	txn.c = c
	fn(txn)
}

type Txn[T any, U Value[T]] struct {
	c *Controller[T, U]
}

func (txn *Txn[T, U]) New(t T) {
	u := U(&t)
	u.SetID(strconv.Itoa(txn.c.idx))
	txn.c.idx++
}

func (txn *Txn[T, U]) Update(key string, fn func(T) T) {
	v, ok := txn.c.m[key]
	if !ok {
		return
	}

	txn.c.m[key] = fn(v)
}

type testType struct {
	id  string
	val string
}

func (t *testType) SetID(id string) {
	t.id = id
}

type Value[T any] interface {
	*T
	SetID(string)
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Hold

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions