Skip to content

proposal: context: functional interfaces #62017

@eccles

Description

@eccles

Description

The context.Context fulfils 3 different purposes:

  • bag of values
  • deadline
  • cancellation.

These different functionalities are not apparent in any API - one has to rely on documentation or read the source code to find out which of the different functionalities is expeceted from the user of any specific API.

I proppose that we take a leaf out of the io.Reader, io.ReadWriter ... interfaces in the io package and define:

  • context.Canceller
  • context.Values
  • context.Deadline
  • context.DeadLineCanceller
  • context.ValuesCanceller
  • context.ValuesDeadline
  • context.Context - all of them for backwards compatibility

API authors can then specify the correct context and this will document in the code the expected context behaviour.

Cons:

  • Some packages will parse the context and act accordingly and this scheme will not work for them without some modification. For example the azure-sdk-for-go will enact a Timeout if the passed in context has a Timeout attribute - otherwise it reverts to an internal retry with backoff.
  • adopting this for any API will probably cause a major version change.

From experience

Coding guidelines can dictate that a context contain values for general use such as headers or grpc metadayta. This leads to the decision to mandate that every network call uses a common context without realising that this common context might also contain a deadline which on every call becomes shorter and shorter leading to general flakiness. Fixing this in a large codebase without knowing what is expected of any passed in context is not trivial perhaps.

Hence the recent introduction of context.WithoutCancel().

I would assert that if we had the above subcontexts then WithoutCaancel may not be required.

Activity

changed the title [-]proposal: affected/package: context: functional interfaces[/-] [+]proposal: context: functional interfaces[/+] on Aug 14, 2023
added this to the Proposal milestone on Aug 14, 2023
apparentlymart

apparentlymart commented on Aug 14, 2023

@apparentlymart

Hi @eccles,

The context.Context mechanism's primary mission is to allow cross-cutting concerns to travel across API boundaries without the entire application needing to agree on what those cross-cutting concerns are.

For example, in my own application I might have decided to use a particular distributed tracing instrumentation API, but it's unlikely that third-party libraries I'm using will have made the same decision. If I'm using a function in that third-party library to indirectly call a function in my own application -- a typical example being stdlib net/http.Server/Client calling my own application's http.Handler or httptrace.ClientTrace -- I cannot modify net/http's API to specify that it should expect and pass downstream a context.Values specifically.

With that said, I feel unsure about how the more specific interfaces you described here would be used. You say "API authors can then specify the correct context", but you've not described how the API author would decide which type to use.

If you are imagining using this only for calls between functions in a single codebase then indeed for that case I could imagine how that might work, but that situation is not the scenario that the context package API is intended for.

Of course that doesn't mean that the scope of context couldn't grow to better support that situation, but if that is your intention then I'd suggest including some concrete examples of how you'd use this in real code so that the value proposition is easier to see.

moved this to Incoming in Proposalson Aug 14, 2023
ianlancetaylor

ianlancetaylor commented on Aug 14, 2023

@ianlancetaylor
Contributor
eccles

eccles commented on Aug 15, 2023

@eccles
Author

Thank you @apparentlymart for your comments.

I am no proposing that we get rid of the generic context.Context. Just simply making it clearer for any particular API on how that AP is expected to be used with regards to the required context.Context argument.

So for example calling a listener of some kind (httpserver or similar):

  func (s *service) Listen(ctx context.Cancel, handle Handler)

which indicates that this function could be cancelled

or

   func (c *Client) Send(ctx context.ValuesDeadline, msg []byte)

which indicates that a timeout should be specified in the context and the Values will be used (maybe in the headers...)

or

    func (c *Client) Send( ctx context.Deadline, msg []byte)

which indicates that only a deadline will be expected in the context.

eccles

eccles commented on Jun 25, 2024

@eccles
Author

Just for emphasis this proposal simply aims to make the intent of the API of any package clearer.

neild

neild commented on Jun 26, 2024

@neild
Contributor

The advantage of context.Context is that we have a single type used across the ecosystem to carry cross-cutting concerns across API boundaries. There are various unfortunate aspects to how Contexts are defined, but they are still widely used because a single, common type outweighs the negatives. Splitting Context into a variety of types would undo that advantage.

eccles

eccles commented on Aug 14, 2024

@eccles
Author

@neild Thanks for your comment but my experience in trying to figure out how a generic context argument is intended to be used and having to resort to reading the many layers of code involved in the third party package contradicts. I see context.context as some form of God object whose intended use is unclear.

We have precedent in the way io.Reader and its related interfaces are constructed and this seems to be a good pattern.

seankhliao

seankhliao commented on May 11, 2025

@seankhliao
Member

I don't think this is a direction we want to go in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Incoming

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @apparentlymart@neild@eccles@ianlancetaylor@gopherbot

        Issue actions

          proposal: context: functional interfaces · Issue #62017 · golang/go