TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Context should go away for Go 2 (2017)

131 点作者 hiohio4 个月前

22 条评论

captainmuon4 个月前
This is about an explicit argument of type &quot;Context&quot;. I&#x27;m not a Go user, and at first I thought it was about something else: an implicit context variable that allows you to pass stuff deep down the call stack, without intermediate functions knowing about it.<p>React has &quot;Context&quot;, SwiftUI has &quot;@Environment&quot;, Emacs LISP has dynamic scope (so I heard). C# has AsyncLocal, Node.JS AsyncLocalStorage.<p>This is one of those ideas that at first seem really wrong (isn&#x27;t it just a global variable in disguise?) but is actually very useful and can result in cleaner code with <i>less</i> globals or less superfluous function arguments. Imagine passing a logger like this, or feature flags. Or imagine setting &quot;debug = True&quot; before a function, and it applies to everything down the call stack (but not in other threads&#x2F;async contexts).<p>Implicit context (properly integrated into the type system) is something I would consider in any new language. And it might also be a solution here (altough I would say such a &quot;clever&quot; and unusual feature would be against the goals of Go).
评论 #42778493 未加载
评论 #42784853 未加载
评论 #42780294 未加载
评论 #42780616 未加载
评论 #42778655 未加载
评论 #42778202 未加载
评论 #42780205 未加载
评论 #42779429 未加载
评论 #42780768 未加载
评论 #42778283 未加载
评论 #42801147 未加载
评论 #42779771 未加载
评论 #42779857 未加载
评论 #42778687 未加载
kalekold4 个月前
&gt; If you use ctx.Value in my (non-existent) company, you’re fired<p>This is such a bad take.<p>ctx.Value is incredibly useful for passing around context of api calls. We use it a lot, especially for logging such context values as locales, ids, client info, etc. We then use these context values when calling other services as headers so they gain the context around the original call too. Loggers in all services pluck out values from the context automatically when a log entry is created. It&#x27;s a fantastic system and serves us well. e.g.<p><pre><code> log.WithContext(ctx).Errorf(&quot;....&quot;, err)</code></pre>
评论 #42778875 未加载
评论 #42778695 未加载
评论 #42778823 未加载
评论 #42781998 未加载
bheadmaster4 个月前
Contexts in Go are generally used for convenience in request cancellation, but they&#x27;re not <i>required</i>, and they&#x27;re not the only way to do it. Under the hood, a context is just a channel that&#x27;s closed on cancellation. The way it was done before contexts was pretty much the same:<p><pre><code> func CancellableOp(done chan error &#x2F;* , args... *&#x2F;) { for { &#x2F;&#x2F; ... &#x2F;&#x2F; cancellable code: select { case &lt;-something: &#x2F;&#x2F; ... case err := &lt;-done: &#x2F;&#x2F; log error or whatever } } } </code></pre> Some compare context &quot;virus&quot; to async virus in languages that bolt-on async runtime on top of sync syntax - but the main difference is you can compose context-aware code with context-oblivious code (by passing context.Background()), and vice versa with no problems. E.g. here&#x27;s a context-aware wrapper for the standard `io.Reader` that is completely compatible with `io.Reader`:<p><pre><code> type ioContextReader struct { io.Reader ctx context.Context } func (rc ioContextReader) Read(p []byte) (n int, err error) { done := make(chan struct{}) go func() { n, err = rc.Reader.Read(p) close(done) }() select { case &lt;-rc.ctx.Done(): return 0, rc.ctx.Err() case &lt;-done: return n, err } } func main() { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() rc := ioContextReader{Reader: os.Stdin, ctx: ctx} &#x2F;&#x2F; we can use rc in io.Copy as it is an io.Reader _, err := io.Copy(os.Stdout, rc) if err != nil { log.Println(err) } } </code></pre> For io.ReadCloser, we could call `Close()` method when context exits, or even better, with `context.AfterFunc(ctx, rc.Close)`.<p>Contexts definitely have flaws - verbosity being the one I hate the most - but having them behave as ordinary values, just like errors, makes context-aware code more understandable and flexible.<p>And just like errors, having cancellation done automatically makes code more prone to errors. When you don&#x27;t put &quot;on-cancel&quot; code, your code gets cancelled but doesn&#x27;t clean up after itself. When you don&#x27;t select on `ctx.Done()` your code doesn&#x27;t get cancelled at all, making the bug more obvious.
评论 #42780587 未加载
评论 #42778885 未加载
评论 #42779062 未加载
评论 #42779045 未加载
rednafi4 个月前
This article is from 2017!<p>As others have already mentioned, there won&#x27;t be a Go 2. Besides, I really don&#x27;t want another verbose method for cancellation; error handling is already bad enough.
评论 #42778415 未加载
the_gipsy4 个月前
&gt; This probably doesn’t happen often, but it’s prone to name collisions.<p>It&#x27;s funny, it really was just using strings as keys until quite recently, and obviously there were collisions and there was no way to &quot;protect&quot; a key&#x2F;value, etc.<p>Now the convention is to use a key with a private type, so no more collisions. The value you get is still untyped and needs to be cast, though. Also there are still many older libraries still uses strings.
评论 #42778804 未加载
mukunda_johnson4 个月前
&gt; It’s very similar to thread-local storage. We know how bad of an idea thread-local storage is. Non-flexible, complicates usage, composition, testing.<p>I kind of do wish we had goroutine local storage though :) Passing down the context of the request everywhere is ugly.
评论 #42785185 未加载
评论 #42779740 未加载
评论 #42778122 未加载
评论 #42778588 未加载
nickcw4 个月前
Contexts implement the idea of cancellation along with go routine local storage and at that they work very well.<p>What if for the hypothetical Go 2 we add an implicit context for each goroutine. You&#x27;d probably need to call a builtin, say `getctx()` to get it.<p>The context would be inherited by all go routines automatically. If you wanted to change the context then you&#x27;d use another builtin `setctx()` say.<p>This would have the usefulness of the current context without having to pass it down the call chain everwhere.<p>The cognitive load is two bultins getctx() and setctx(). It would probably be quite easy to implement too - just stuff a context.Context in the G.
alkonaut4 个月前
Was this solved? Is this context only a cancellation flag or does it do something more? The obvious solution for a cancellation trigger would be to have cancellation as an optional second argument. That&#x27;s how it&#x27;s solved in e.g. C#. Failing to pass the argument just makes it CancellationToken.None, which is simply never cancelled. So I&#x2F;O without cancellation is simply foo.ReadAsync(x) and with cancellation it&#x27;s foo.ReadAsync(x, ct).
评论 #42778640 未加载
the_duke4 个月前
Needs a (2017)!
评论 #42778036 未加载
miffy9004 个月前
&gt; First things first, let’s establish some ground. Go is a good language for writing servers, but Go is not a language for writing servers. Go is a general purpose programming language, just like C, C++, Java or Python<p>Really? Even years later in 2025, this never ended up being true. Unless your definition of &#x27;general purpose&#x27; specifically excludes anything UI-related, like on desktop, web or mobile, or AI-related.<p>I know it&#x27;s written in 2017, but reading it now in 2025 and seeing the author comparing it to Python of all languages in the context of it&#x27;s supposed &#x27;general purpose&#x27;ness is just laughable. Even Flutter doesn&#x27;t support go. granted, that seems like a very deliberate decision to justify Dart&#x27;s existence.
评论 #42791366 未加载
评论 #42779893 未加载
评论 #42782477 未加载
mrkeen4 个月前
&gt; If the Go language ever comes to the point where I’d have to write this<p><pre><code> n, err := r.Read(context.TODO(), p) </code></pre> &gt; put a bullet in my head, please.<p>Manually passing around a context everywhere sounds about as palatable as manually checking every return for error.
评论 #42778069 未加载
disintegrator4 个月前
Consider what happens in JavaScript when you declare a function as async. Now everything calling it is infected. Passing around runtime constructs like context in Go (AbortSignal in JS) or an allocator in Zig gives exactly the right level control back to the call and I love it. You can bail out of context propagation at any level of your program if that&#x27;s your desire.
dang4 个月前
Discussed at the time:<p><i>Context should go away for Go 2</i> - <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=14951753">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=14951753</a> - Aug 2017 (40 comments)
skywhopper4 个月前
I agree so strongly with this piece. Go’s context lib is essential, confusing, functional, and should be handled at the language level, but like this author I also have no ideas for what the design should be.
n144q4 个月前
I find &quot;CancellationToken&quot; in VSCode extension APIs quite clear and usable, and not overly complicated. Wonder if anyone has done a conparison of Go&#x27;s context and CancellationToken.
评论 #42786126 未加载
sir_eliah4 个月前
&gt; If you use ctx.Value in my (non-existent) company, you’re fired<p>What a nice attitude.
theThree4 个月前
Context is useful in many cases. In go I have to pass ctx from func to func. In nodejs I can easily create&amp;use context by using AsyncLocalStorage (benefit of single-thread).
mickael-kerjean4 个月前
&gt; If you use ctx.Value in my (non-existent) company, you’re fired<p>I was unsuccessful to convey the same message in my previous company (apart from being fired part). All around the codebase you&#x27;d see function with official argument and unofficial ones via ctx that would panic everything if you forgot it was used 3 layers down (not kidding). The only use case I&#x27;ve seen so far that is not terrible of context value is if you have a layer of opentelemetry as it makes things transparent and as a caller you don&#x27;t have to give a damn how the telemetry is operated under the hood.
pluto_modadic4 个月前
new solution should be: Simple and elegant. Optional, non-intrusive and non-infectious. Robust and efficient. Only solves the cancelation problem.<p>okay... so they dodged the thing I thought was going to be interesting, how would you solve passing state? e.g. if I write a middleware for net&#x2F;http, I have to duplicate the entire http.Request, and add my value to it.
rw_panic0_04 个月前
there&#x27;s no Go 2
评论 #42779661 未加载
steve_adams_864 个月前
&gt; If you use ctx.Value in my (non-existent) company, you’re fired<p>Yeah, okay. I tried to find reasons you&#x27;d want to use this feature and ultimately found that I really, really dislike it.
jbub4 个月前
2017!!!