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

proposal: constraints: add ReadOnlyChan and WriteOnlyChan #48366

Closed
ianlancetaylor opened this issue Sep 13, 2021 · 10 comments
Closed

proposal: constraints: add ReadOnlyChan and WriteOnlyChan #48366

ianlancetaylor opened this issue Sep 13, 2021 · 10 comments
Labels
FrozenDueToAge generics Issue is related to generics Proposal
Milestone

Comments

@ianlancetaylor
Copy link
Member

ianlancetaylor commented Sep 13, 2021

The currently accepted proposal for the constraints package (#45458) adds a constraint Chan. In #47319 (comment) @Merovius points out that does not support read-only and write-only channel types. This proposal is to add new constraints

type ReadOnlyChan[Elem any] interface { ~<-chan Elem }
type WriteOnlyChan[Elem any] interface { ~chan <- Elem }
@ianlancetaylor ianlancetaylor added Proposal generics Issue is related to generics labels Sep 13, 2021
@ianlancetaylor ianlancetaylor added this to the Proposal milestone Sep 13, 2021
@uluyol
Copy link
Contributor

uluyol commented Sep 14, 2021

Should these be

type ReadOnlyChan[Elem any] interface { <-chan Elem | chan Elem }
type WriteOnlyChan[Elem any] interface { chan <- Elem | chan Elem }

instead? That way func f[E any, C ReadOnlyChan[E]](chans []C) would accept both a slice of <-chan and a slice of chan.

@smasher164
Copy link
Member

Is there a reason why the Chan constraint uses the approximation element ~chan Elem, while ReadOnlyChan and WriteOnlyChan don't?

@ianlancetaylor
Copy link
Member Author

@smasher164 Thanks, fixed.

@andig
Copy link
Contributor

andig commented Sep 15, 2021

Should these be

type ReadOnlyChan[Elem any] interface { <-chan Elem | chan Elem }
type WriteOnlyChan[Elem any] interface { chan <- Elem | chan Elem }

instead? That way func f[E any, C ReadOnlyChan[E]](chans []C) would accept both a slice of <-chan and a slice of chan.

Isn't a chan always a <-chan? I don't think you can restrict- even today- a chan argument to be read-only?

@Merovius
Copy link
Contributor

@andig Yes, you can. By assigning it to <-chan. after that, any write-operation on it becomes invalid and you can't assign it back to chan. https://play.golang.org/p/GSu7Inzp2QY

@Merovius
Copy link
Contributor

@andig Ah, I think I understand what you mean. You can't restrict it so that only a <-chan can be passed, it is always possible to pass a chan (as chan is assignable to <-chan).

But, it's still useful for a function to declare that it will only do read or write operations on a channel - both as a signal to the caller and to get compiler-checks that the function doesn't do it. That's what's meant here.

@andig
Copy link
Contributor

andig commented Sep 15, 2021

@andig Ah, I think I understand what you mean. You can't restrict it so that only a <-chan can be passed, it is always possible to pass a chan (as chan is assignable to <-chan).

But, it's still useful for a function to declare that it will only do read or write operations on a channel - both as a signal to the caller and to get compiler-checks that the function doesn't do it. That's what's meant here.

Absolutely. I was trying to point out that { <-chan Elem | chan Elem } is redundant to { <-chan Elem }

@Merovius
Copy link
Contributor

As an example: In this code, Map declares that it only reads from the channel that you pass in and that the channel it returns can only be read from. That's useful. But, Map now doesn't work with type MyChan chan int.

I'm not 100% convinced that we need that. For example, AFAIK there currently is no way for a function to declare that it takes a read-only version of MyChan. It just seems to me, that if we need constraints.Chan, than we should also have this ability. IMO it is more important to declare that a channel can only be read or only be written, than it is to enable us to work with custom channel types.

TBQH, I'd probably rather do away with constrains.Chan for now. The only reason I ever used defined channel types was if they had very specific semantics - for example, I might use a buffered type Semaphore chan struct{} as a semaphore. But in those cases, that defined type probably shouldn't be used with generic channel functions. So, while I'm convinced of constraints.Slice and constraints.Map, I'm far less convinced of constraints.Chan.

@Merovius
Copy link
Contributor

@andig No, as @uluyol points out, while chan T is assignable to chan <- T, it is not identical, which matters for composite types like []chan T, which isn't assignable to []chan <- T.

@ianlancetaylor
Copy link
Member Author

I'm withdrawing this proposal in favor of #48424.

@golang golang locked and limited conversation to collaborators Oct 8, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge generics Issue is related to generics Proposal
Projects
None yet
Development

No branches or pull requests

6 participants