Repository: go
Issue: proposal: spec: permit write defined type in type term
Labels: LanguageChange,Proposal,generics,LanguageChangeReview

### Author background

**Would you consider yourself a novice, intermediate, or experienced Go programmer?**

Depends on who am I comparing to and what are the metrics that define these levels. A few objective measures: Using Go since 2018, 1 year of cloud-native related industrial backend development, 3 years of research prototyping in 3D graphics associated with rendering and geometry processing, spare time projects in Go which can be found in my GitHub profile, contributing to Go project, etc. Probably "experienced"?

**What other languages do you have experience with?**

C++ (wrote a book), Python and R (for research and relevant data analysis), JS and TypeScript (for teaching in university), etc.

### Related proposals

**Has this idea, or one like it, been proposed before?**

I don't know, and I hope not. There were some discussions in #52295.

**Does this affect error handling?**

Probably not.

**Is this about generics?**

Yes.

### Proposal

**What is the proposed change?**

I propose to permit writing defined types in type terms. In this case,
we are allowed to use defined types in a type constraint.

For instance, the following code does not work in Go 1.18 because the tilde operator can only be applied to a type other than a defined type:

```go
package main

type Type struct{}

type MyType Type

func F1[T ~Type](t T)     {} // ERROR: invalid use of ~ (underlying type of Type is struct{})
func F2[T ~struct{}](t T) {} // OK
func F3[T ~MyType](t T)   {} // ERROR: invalid use of ~ (underlying type of MyType is struct{})

func main() {
	x := Type{}
	y := MyType{}
	F1(x) // ERROR: cannot implement ~Type (empty type set)
	F1(y) // ERROR: cannot implement ~Type (empty type set)

	F2(x) // OK
	F2(y) // OK
}
```

**Who does this proposal help, and why?**

See some more elaborated examples in #52295.

**Please describe as precisely as possible the change to the language.**

I spend sometime to read into the relevant part of the spec, then I prepared a change to the current 1.18 spec for discussion, see: https://go.dev/cl/400095

**What would change in the language spec?**


I spend sometime to read into the relevant part of the spec, then I prepared a change to the current 1.18 spec for discussion, see: https://go.dev/cl/400095

**Please also describe the change informally, as in a class teaching Go.**

Allow using `~` following with a defined type.

**Is this change backward compatible?**

I think and hope so. But I am not entirely an expert on the spec.

From what I see so far is that: with this change, it unlocks code that cannot be written before.
Hence I would expect this is a backward compatible change.

Possibly some change of description regarding what is T's underlying type (I hope the wording is correct), but I guess this only stays on a conceptual level and does not affect the practice (?) Again, I am not a language expert.

**Orthogonality: how does this change interact or overlap with existing features?**

I don't think there is an overlap, but I don't know enough about the spec.

**Is the goal of this change a performance improvement?**

Probably not, but I am not certain on how the change could associate with performance.

### Costs

**Would this change make Go easier or harder to learn, and why?**

I think it at least well addresses some of my confusion regarding the use of the language feature of type constraints. See discussions in #52295.
Thanks @cherrymui for the discussion and suggestions.

**What is the cost of this proposal? (Every language change has a cost).**

Sorry, I don't know enough, probably complicating the concept of "underlying type" for people reading into the spec?

**How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected?**

Sorry, I don't know enough about this aspect.

**What is the compile time cost?**

Sorry, I don't know enough about this aspect.

**What is the run time cost?**

Sorry, I don't know enough about this aspect.

**Can you describe a possible implementation?**

Sorry, I am not familiar enough with the current implementation details and am also not yet a compiler expert. I might imagine that inferring the underlying type of a type that is redefined multiple times might be slow or slightly inconvenient (?)

**Do you have a prototype? (This is not required.)**

For the spec, yes: https://go.dev/cl/400095
For the implementation, no.