Go version
go1.23 and go tip
Output of go env
in your module/workspace:
n/a, using go.dev/play
What did you do?
https://go.dev/play/p/-psvliJDE_j
package main
import "fmt"
// Constraint to allow function to operate on a channel,
// regardless of the channel's directionality.
type channelConstraint[T any] interface {
chan T | <-chan T | chan<- T
}
func main() {
var sendOnlyCh chan<- string = make(chan string)
printCap(sendOnlyCh)
// Needs to be:
printCap[string](sendOnlyCh)
var receiveOnlyCh <-chan int = make(chan int, 1)
printCap(receiveOnlyCh)
// Needs to be:
printCap[int](receiveOnlyCh)
bidiCh := make(chan any)
printCap(bidiCh)
// Needs to be:
printCap[any](bidiCh)
}
// printCap prints the capacity of ch,
// regardless of ch's directionality.
func printCap[T any, C channelConstraint[T]](ch C) {
fmt.Println(cap(ch))
}
I want to write a small utility that takes a specific action that is determined by a channel's length and/or capacity. In this codebase, there are a general mix of directional and bidirectional channels. I thought I would be able to write a constraint such that my helper can accept a channel of any directionality. And I can indeed write that constraint, but when I call a function with that constraint, I have to provide the channel's element type as a type parameter in order to get the program to compile.
I am surprised that I have to provide the channel's element type, but maybe I am missing something about constraints or generics.
What did you see happen?
./prog.go:13:10: in call to printCap, cannot infer T (prog.go:28:15)
What did you expect to see?
I expected that printCap(ch)
would compile; that I would not have to write printCap[int](ch)
.
I tried searching the issues for variations of "constraints", "channels", and "direction" or "directionality" but I was not able to find any issues that looked similar.
Comment From: gabyhelp
Related Issues and Documentation
- go/types, types2: make constraint type inference more flexible for some channel types (?) #45920 (closed)
- go/types, cmd/compile/internal/types2: type inference limitation leads to incorrect result for directed channel type constraint #65202
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Comment From: ianlancetaylor
CC @griesemer
I think we would need a special type inference rule for channel types.
Note that I think that your program isn't going to work anyhow. The cap(ch)
call isn't permitted, though that would be fixed by #63940.
Comment From: mark-rushakoff
Adjusting the code to remove the lines that failed compilation, it does appear that cap(ch)
is reported correctly, on go1.23. https://go.dev/play/p/jS1_QIeyrUF
It looks like len(ch)
works too.
Comment From: griesemer
What @ianlancetaylor said. The issue here is that there's no core type for the constraint. At the moment inference does work if the constraint was just chan T | <-chan T
or chan T | chan<- T
(there's a core type) but instantiation doesn't work of course for the one direction that's not in the constraint.
This might also be addressed by #63940.
Comment From: griesemer
Marking for 1.24 - not promising that this will be addressed, but so I keep an eye on it while investigating #63940.
Comment From: griesemer
Moving to 1.25.