Skip to content

proposal: spec: allow selective method embedding for interface definitions (like TypeScript's Pick) #73373

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

Closed
1 of 4 tasks
rarick opened this issue Apr 14, 2025 · 3 comments
Closed
1 of 4 tasks
Labels
LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee LanguageProposal Issues describing a requested change to the Go language specification. Proposal
Milestone

Comments

@rarick
Copy link

rarick commented Apr 14, 2025

Go Programming Experience

Intermediate

Other Languages Experience

No response

Related Idea

  • Has this idea, or one like it, been proposed before?
  • Does this affect error handling?
  • Is this about generics?
  • Is this change backward compatible? Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit

Has this idea, or one like it, been proposed before?

No - I was unable to find related proposals. I would expect there to be existing proposals, but was unable to find any. Please link if I am mistaken, I'd be interested in reading discussion around this.

Does this affect error handling?

No

Is this about generics?

No

Proposal

Background:
Effective Go encourages the use of defining small, consumer-oriented interfaces. In practice, this results in some toil in copying signatures as well as importing the necessary paths to correctly define those signatures.

For example:

// `github.com/some/go/library`
import (
    transitive "github.com/some/transitive/dependency"
)

type Client struct {}

(c *Client) Put(ctx context.context, input *transitive.Input, ...func(*transitive.Options)) (*transitive.Output, error) {
  ...
}

Now a consumer-defined interface must match this declaration and imports:

// `github.com/some/limplementer`
import (
    "github.com/some/go/library"
    transitive "github.com/some/transitive/dependency"
)

type Putter interface {
    Put(ctx context.context, input *transitive.Input, ...func(*transitive.Options)) (*transitive.Output, error)
}

While not a large amount of toil, the developer's goal will very frequently be to declare the exact same signature from some type, so there is some opportunity to simplify this.

Proposal:
Introduce syntax for consumer-side interfaces to selectively include methods from existing interfaces or types (similar to TypeScript's Pick), e.g.:

type ConsumerInterface interface {
    io.ReadCloser.Read
    (*os.File).Write
}

This allows defining ConsumerInterface with just the Read method from io.ReadCloser and Write from *os.File.

Pros:

  • Further encourages interface usage by reducing friction
  • Reduces boilerplate
  • Improves readability for consumer-defined APIs

Drawbacks:

  • Increases language complexity
  • Less "WYSIWYG"
  • Can obscure interface method sources
    • Especially in the case where selections may propagate across
  • May complicate tooling (e.g., go doc, gopls)
  • May encourage bad interface definition

Language Spec Changes

No response

Informal Change

No response

Is this change backward compatible?

Yes

Orthogonality: How does this change interact or overlap with existing features?

Go currently allows for the composition of interface types through interface embedding:

// package `io`
type ReadCloser interface {
	Reader
	Closer
}

This proposal is similarly for the composition of an interface, but through selective embedding.

Would this change make Go easier or harder to learn, and why?

Yes. It is another feature and a new way to compose an interface.

Cost Description

  • Increases language complexity
  • Less "WYSIWYG"
  • Can obscure interface method sources
    • Especially in the case where selections may propagate across
  • May complicate tooling (e.g., go doc, gopls)
  • May encourage bad interface definition

Changes to Go ToolChain

No response

Performance Costs

No response

Prototype

No response

@rarick rarick added LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee Proposal labels Apr 14, 2025
@gopherbot gopherbot added this to the Proposal milestone Apr 14, 2025
@gabyhelp gabyhelp added the LanguageProposal Issues describing a requested change to the Go language specification. label Apr 14, 2025
@seankhliao
Copy link
Member

seankhliao commented Apr 14, 2025

If you're already going to pull in a dependency to define an interface, you might as well define the interface in the dependency itself or in a common package for your consumers.
Pulling in your implementation to define an interface doesn't achieve the decoupling advocated for in effective go.

see also #23886

@seankhliao seankhliao closed this as not planned Won't fix, can't repro, duplicate, stale Apr 14, 2025
@rarick
Copy link
Author

rarick commented Apr 14, 2025

Pulling in your implementation to define an interface doesn't achieve the decoupling advocated for in effective go.

Ah agreed, I had been thinking "I'm copying the signature, so what means I'm pulling in the dependency anyway". But not quite true. In the example, I would only need a dependency on transitive, while the proposal increases the coupling to (library, transitive). Darn.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee LanguageProposal Issues describing a requested change to the Go language specification. Proposal
Projects
None yet
Development

No branches or pull requests

4 participants