What won't be in Go 2.0?

polaris · · 42 次点击    
<p>There&#39;s been a lot of discussion about generics and what might be added to Go 2.0.</p> <p>What could you hypothetically see replaced/redesigned/removed from the language or the standard library?</p> <hr/>**评论:**<br/><br/>brokedown: <pre><p>I know its in /x/ but they should really just <a href="https://godoc.org/golang.org/x/net/websocket">drop their WebSocket library</a> and adopt the Gorilla package in its place. The doc page already suggests you use Gorilla instead.</p></pre>nhooyr: <pre><p>or the new gobwas/ws package.</p></pre>brokedown: <pre><p>Indeed I need to evaluate this library as well. It&#39;s stated goals are around higher performance than other packages but they have some nice utility functions that could remove some of the boilerplate as well.</p></pre>GrayFox89: <pre><p>I use both <code>x/net/websocket</code> and <code>gorilla/websocket</code>; I have to admit that i like gorilla&#39;s upgrade better, and also it has streaming support that is missing from the <code>x</code> package, ie. <code>x</code>&#39;s frame writer forces fin=true on every Write(), instead of only on Close(), which only seems like a bug when I think about it.</p></pre>sh41: <pre><p>I think the API of <code>x/net/websocket</code> is much nicer and friendlier. I know its implementation is not as advanced.</p></pre>sxan: <pre><p>Hopefully Michal&#39;s well-written article about Context will motivate it being replaced. I&#39;m crossing my fingers on that one.</p> <p>For reference, <a href="https://faiface.github.io/post/context-should-go-away-go2/">https://faiface.github.io/post/context-should-go-away-go2/</a></p></pre>programming_acct: <pre><p>Damn, that&#39;s pretty compelling. </p></pre>martingxx: <pre><p>I found that article a bit confused and unhelpful because it didn&#39;t propose anything better that solved the cancellation problem. Not wanting to see context everywhere doesn&#39;t make any more sense than not wanting to see errors everywhere (unchecked exceptions anyone?). In such a highly concurrent language, you should expect to see cancellation constructs often. Its not a problem it&#39;s a solution.</p></pre>faiface: <pre><p>Errors and Context are infectious in a very different way.</p> <p>Errors infect the code that uses them.</p> <p>Context infects the code that is used by another Context-equipped code.</p> <p>The latter kind of spreading is much more evil.</p></pre>martingxx: <pre><p>How can any code infect the code it calls? I don&#39;t get it.</p></pre>faiface: <pre><p>It infects the developers who create that code. Context needs to be propagated to all blocking operations for cancelation (= code called from Context-equipped code). Thus, developers attach it to functions which will be called from server code.</p></pre>martingxx: <pre><p>Context is needed whenever anything down the call stack can block. I don&#39;t see how that&#39;s much different from errors. Errors (unless they can he fully handled there need propogating up the stack even if one of the things in there doesn&#39;t care about it.</p></pre>faiface: <pre><p>You say it yourself. Context is needed whenever anything <em>down</em> the stack can block. But it&#39;s needed <em>down</em> the stack. It propagates down the stack. Errors only propagate up the stack.</p> <p>EDIT: I messed it up a bit</p></pre>SteveMcQwark: <pre><p>Something down the stack can block is the same as something down the stack can error. That&#39;s propagating up the stack <em>from</em> down the stack.</p> <p>What&#39;s propagating <em>down</em> the stack is the need to be able to stop what you&#39;re doing. If you need to be able to stop what you&#39;re doing, then you need any long running (blocking or non-blocking) code you use to be able to stop what <em>it&#39;s</em> doing. The need to be able to be interrupted from outside is what propagates down the stack.</p></pre>parenthephobia: <pre><p>I think Erlang has a better solution for cancellation: although that is not all Context is used for.</p> <p>In Erlang, one can link two processes - roughly equivalent to goroutines - so that if one panics, so does the other one. One can also check/wait for a process to panic, or end normally. So a job can start up a tree of processes which are linked together, and then one of them can panic when it learns that the job needs to be cancelled, and then all the others panic.</p> <p>Another process not linked to them will be waiting for the root process to stop and then respond accordingly. e.g. If they produced a result, pass that on to whoever wants it; if they panicked because of cancellation, just carry on; if they panicked because one of the processes fell over, restart the job tree.</p></pre>sxan: <pre><p>The problem with Context is orthogonal to monads in Haskell. Monads are possibly the worst aspect of Haskell, and they also exist because they tried to solve what should have been solved in the language through passed-in variables. As Michal points out, it&#39;s hard to avoid having Contexts infect code that doesn&#39;t need it. It&#39;s a trap, and a particularly bad one at that. </p> <p>Michael says, clearly, he doesn&#39;t have a solution. Once we&#39;re in 2.0, though, if Contexts are there we&#39;ll be stuck with them indefinitely. I, for one, hope we can avoid that.</p></pre>SteveMcQwark: <pre><p>Monads aren&#39;t that bad. Everybody trying to understand what they <em>really</em> mean creates a bunch of unnecessary hysteria. All they <em>really</em> are is a way to chain operations where the outputs don&#39;t quite match up with the inputs. As long as there&#39;s a consistent relationship between inputs and outputs (embodied by the <code>return</code> function), and a systematic way to use the outputs as inputs (encapsulated by the <code>bind</code> function) which composes in a sane way, you have a monad. For any collection you can iterate over, <code>bind</code> is just <code>flat_map</code>, applying a function to each element to produce another collection for each, and then concatenating the results.</p> <p>You could technically get context to work as a monad. Functions would just have to be generic over the type of monad so you can opt to use a context or not, depending on need. The problem is it requires fairly powerful generics (Rust can&#39;t handle it yet) and a fair bit of compiler optimization to rewrite the two steps—chaining operations and <em>then</em> executing them—into something more immediate and sane.</p></pre>bupku5: <pre><p>please make struct tags part of the language and not just some DSL encoded as a string</p></pre>very-little-gravitas: <pre><p>The problem with struct tags runs deeper than that. The problem is that they offer a way to attempt to map fields to various other things (db cols, json etc), when in fact go code can be used to do that already. So they could just remove them instead and it&#39;d be far cleaner. You can do everything struct tags do with go code instead - simply assign your fields directly to whatever thing aligns with them, with the appropriate transformations and checks (I do a lot of work in go involving dbs and json and have successfully avoided using them so far). </p> <p>They&#39;re not actually necessary and like magic comments I think cause more problems than they solve. </p> <p>These are the two things (magic comments, struct tags) I&#39;d remove in a putative Go 2, but the struct tags one would be too painful to force on current users so it&#39;ll never happen. </p></pre>winger_sendon: <pre><p>It will be more verbose. What we need is type safe &#34;struct tags&#34;, like attributes in C#</p></pre>tv64738: <pre><p>Oh, it&#39;s worse, struct tags are a language inside a language inside a language. The struct definition is the outermost language, the `` is the middle, and the someidentifier:&#34;...&#34; is the innermost language.</p></pre>jeremiahs_bullfrog: <pre><p>I hope they rethink variable declarations, new and make. There&#39;s far too many ways to do the same thing. I&#39;d be fine getting rid of := since it really doesn&#39;t add anything and is easy to miss.</p> <p>I also hope they revisit nil vs interface{}(nil) (they should be equivalent IMO).</p></pre>Sythe2o0: <pre><p>I love :=. Please don&#39;t take it away.</p></pre>jeremiahs_bullfrog: <pre><p>Something&#39;s gotta give. There&#39;s way to many ways to declare/instantiate variables, such as:</p> <pre><code>var x T var x = T(...) var x T = ... var x T = T(...) x := T(...) </code></pre> <p>And if T is a struct:</p> <pre><code>x := T{...} x := T{&lt;name&gt;: ...} </code></pre> <p>But why doesn&#39;t this work?</p> <pre><code>var x T = {...} </code></pre> <p>And are these both equivalent?</p> <pre><code>x := new(T) x := &amp;T{} </code></pre> <p>In fact, the whole existence of new is terrible, and I think the only reason they have it is because otherwise there&#39;s no way to create a new primitive pointer without a temporary variable, but it causes all kinds of confusion since it&#39;s only rarely useful and make it not often what you want.</p> <p>There should be only one obvious way to do something, and there are currently multiple with variable declaration and instantiation. I pick on := because it literally adds nothing besides syntax sugar over <code>var x = ...</code>.</p></pre>Sythe2o0: <pre><p>I think there&#39;s been discussion about removing <code>new</code> before, but it wasn&#39;t because of backwards compatibility. <code>:=</code> is a lot more terse than using <code>var</code>, and I more or less only use <code>var</code> in bottom-level blocks or when necessary.</p></pre>jeremiahs_bullfrog: <pre><p>Eh, I don&#39;t care too much what the solution is, I just think it&#39;s just unnecessary how many subtle variations there are.</p></pre>JHunz: <pre><p>Is there a way to declare multiple variables at a time and assign them to the results of a multi-return function call without := ?</p></pre>jeremiahs_bullfrog: <pre><p>This works:</p> <pre><code>func do() (int, int) { return 1, 2 } var a, b = do() </code></pre> <p>However, this doesn&#39;t seem to work in an if statement, but := does. The easy solution is to allow <code>if var a, b = do(); a != b { }</code>.</p> <p>One case where it breaks down is if one of the variables is already defined in the same block. := will not redeclare the variable, though it will shadow it if it&#39;s in a different block, which I think is a bit dangerous, especially since it could bite you in a refactor.</p></pre>parenthephobia: <pre><p>If we accept it&#39;s necessary to have <code>var x T</code>, and that it&#39;s desirable to have <code>var x = ...</code> so you don&#39;t have to type a type name when the compiler must know the type itself, and that <code>T(...)</code> should exist as an expression, then we must allow <code>var x = T()</code> or complicate the compiler by putting in code to prohibit it.</p> <p>I prefer <code>x := ...</code> simply because it&#39;s shorter than <code>var x = ...</code>. Also, I think <code>if var x = ...</code> looks ugly.</p> <p>I agree about <code>new</code>. There&#39;s no good reason <code>&amp;int(42)</code> <em>shouldn&#39;t</em> work.</p> <p>I&#39;m not sure about <code>make</code>. You could replace its use with &#34;calling&#34; a type: <code>make([]int, 10, 100)</code> to <code>[]int(10, 100)</code>. But, there is an established use of <code>T(...)</code> as a conversion, and it doesn&#39;t seem very &#34;Go-like&#34; to overload certain types with &#34;conversions&#34; that aren&#39;t.</p> <p><em>If</em> we had generics, we could have, say, <code>arrays.make{[]int}(10, 100)</code>, but without them I don&#39;t think there&#39;s a type safe way to do what make does without dedicated syntax or punning on conversions.</p></pre>jeremiahs_bullfrog: <pre><blockquote> <p>Also, I think if var x = ... looks ugly.</p> </blockquote> <p>Eh, eye of the beholder I suppose. Rust has <code>if let</code> (different semantics though) so it&#39;s not entirely out of left field.</p> <p>While I like the convenience of <code>:=</code>, I just don&#39;t think it&#39;s justified since <code>var</code> is still necessary (though I suppose I&#39;d be open with eliminating <code>var</code> in favor of <code>:=</code>). I just don&#39;t like having several right ways of doing something.</p></pre>SteveMcQwark: <pre><p>They wanted to replace <code>new(T)</code> with <code>make(*T)</code>, but the community had gotten so used to defending the dichotomy that the autoimmune response killed the proposal.</p> <p>The key issue with <code>:=</code> is the implicit shadowing. That&#39;s why there have been proposals to make variable reuse explicit (like <code>v, ^err := ...</code>) so that you don&#39;t accidentally shadow in nested scopes, and making it illegal to shadow a variable with a short variable declaration.</p> <p>You missed</p> <pre><code>var (x int = 1; y int = 2) </code></pre></pre>jeremiahs_bullfrog: <pre><blockquote> <p>make variable reuse explicit</p> </blockquote> <p>I support this. Though I&#39;d prefer to only have one way to declare variables, so <code>:=</code> <strong>or</strong> <code>var</code>.</p> <p>And yes, <code>new</code> should die. I&#39;d prefer to replace <code>make</code> and any other builtin that does something with generic types with something that actually uses generics. It&#39;s weird that <code>make</code> can take 1, 2 or 3 parameters depending on the type of the first.</p></pre>SteveMcQwark: <pre><p><code>var</code> is useful if you need to predeclare something, if you actually want shadowing, or if you need to specify a type such as with a package variable. I don&#39;t see the need to radically pare down the ways to declare variables, since they each have their use cases and there&#39;s not much overlap.</p></pre>jeremiahs_bullfrog: <pre><blockquote> <p>there&#39;s + not much overlap</p> </blockquote> <p>There&#39;s quite a bit of overlap, enough that a couple minor tweaks could put them on feature parity. I just don&#39;t see the need to keep both, and I don&#39;t think that removing one is &#34;radical&#34;, since most languages don&#39;t have this distinction.</p> <p>In fact, I think we should add tuples and use them for multiple return since they&#39;re useful in many other contexts as well. This would make an even stronger case for getting rid of <code>:=</code> since <code>(x, y) := ...</code> looks weird.</p></pre>SteveMcQwark: <pre><p>I meant overlap in usage rather than in functionality. People don&#39;t use <code>var</code> unless they have to.</p></pre>jeremiahs_bullfrog: <pre><p>But that&#39;s only because <code>:=</code> is slightly less typing. The problem is that <code>:=</code> can&#39;t solve all your problems, so it needs what <code>var</code> provides, whereas you can accomplish anything you need with <code>var</code>. Thus <code>var</code> is strictly more powerful than <code>:=</code>, while <code>:=</code> is more convenient.</p> <p>If we make <code>var</code> more convenient, then we can eliminate <code>:=</code>. Let&#39;s do something about shadowed variables (e.g. <code>var x, ^y = ...</code>) and allow <code>var</code> in contexts where <code>:=</code> or <code>=</code> are the only options (<code>for</code>, <code>if</code>, etc).</p> <p>Go is all about orthoganal features, which is why I think <code>:=</code> and <code>var</code> having so much overlap is weird.</p></pre>bupku5: <pre><p>yes <code>new</code> could be eliminated entirely</p></pre>alasijia: <pre><p>:= is ok if it will not shadow outer scope variables. Now var = and := are too overlapped.</p></pre>exch: <pre><p>The first thing that should be done, is get rid of the backwards compatibility requirement with Go 1.x. If you want to fix Go, then fix Go. Don&#39;t just hamfist workarounds in, while trying to avoid stepping on old code.</p></pre>parenthephobia: <pre><p>The issue is to avoid opening a fault line in the Go community. Just abandoning backwards compatibility wholesale isn&#39;t going to go well unless the majority of the userbase is quickly convinced that moving to the new version is a great idea. Python 3, Perl 6 being fine examples of when this goes wrong.</p> <p>Despite that, I think the right sort of idea was Python&#39;s <code>__future__</code> module, or Perl&#39;s <code>use experimental</code>. I think that it&#39;s important to be able to move code across a backwards-incompatible boundary <em>piecemeal</em>, not having to change all of your code at once, and not having to adapt to backwards-incompatible changes at once. Ideally, you&#39;d <em>never</em> need to port code which wouldn&#39;t benefit in some way from being ported.</p> <p>OTOH, there&#39;s a more subtle backwards compatibility issue. Suppose that in a hypothetical future Go has opt-in-able generics, the community adopts them widely, and many popular libraries are converted to export generic types and functions: the people who don&#39;t want to use generics will increasingly find that they can&#39;t find libraries they can use. The Go ecosystem may fracture into generic and non-generic camps, which is unlikely to be good for anyone.</p> <p>For language features that don&#39;t leak through package boundaries, this is probably not an issue. For example, if one can set for a file whether typed interface values will equal nil, nothing outside that file needs to adjust its behaviour accordingly. Even if you disagree with doing that in your code, you can use a library which does that, because importing code which uses that feature doesn&#39;t mean you have to use that feature.</p> <p>The conclusion I&#39;d draw here is that where possible one should prefer backwards incompatible changes that can be isolated to a file or package, and are opt-in. If a backwards incompatible change that inherently effects the consumers of a package must be made, it cannot be opt-in. This also implies that such changes should be based on a reasonable consensus so as to minimize the trauma to those that don&#39;t really want the change: i.e. a hypothetical generics solution shouldn&#39;t be as extreme as Rust.</p></pre>martingxx: <pre><p>I think this needs to be looked at a case at a time. The cost of breaking compatibility is often underestimated but it&#39;s still sometimes worth it if the value is really high enough. A blanket decision to break compatibility of any API even for slight improvements would be unhelpful.</p></pre>exch: <pre><p>Agreed. But the point of Go 2.0, as opposed to 1.x, is sweeping language changes. I think this is big enough to warrant going all-in.</p> <p>The one place where this could be majorly problematic, is having Go 2 programs use the existing standard library. If code becomes incompatible, the entire stdlib would have to be duplicated and fixed to be compatible. Not to mention all the user-made code already out there. I can see how that is imminently undesirable.</p></pre>brokedown: <pre><p>In my opinion, if &#39;go fix&#39; can fix it, it isn&#39;t broken. </p></pre>bupku5: <pre><p>exactly! provide a migrate script or something...otherwise Go will become C++</p></pre>Emacs24: <pre><p>Remove</p> <pre><code>context.Context </code></pre> <p>Combining functionality of cancellation and data storage in one place looks too much like project specific. Go runtime and execution is full of tricks anyway, so why not to add a goroutine cancelation handler?</p></pre>carleeto: <pre><p>A basic UI library would be nice. Gxui came really close. A cross platform UI library for simple applications would make Go accessible to those who think in terms of point and click.</p> <p>Not sure how far along shiny is, but being able to &#34;go get&#34; something that allowed you to create a cross platform UI would be really cool.</p></pre>tv64738: <pre><p>That&#39;s not part of the language.</p></pre>hooluupog: <pre><blockquote> <p>What could you hypothetically see replaced/redesigned/removed from the language or <strong>the standard library</strong>?</p> </blockquote></pre>YEPHENAS: <pre><p>There is no UI package in the standard library. So none can be removed from it.</p></pre>tv64738: <pre><blockquote> <p>What won&#39;t be in Go 2.0?</p> </blockquote></pre>martingxx: <pre><p>Remove the keywords: new &amp; fallthrough</p> <p>Drop packages: container , encoding/csv, database/sql. </p></pre>winger_sendon: <pre><p>Whats wrong with fallthrough?</p></pre>slewiskelly: <pre><p>I&#39;m wondering this also...?</p></pre>parenthephobia: <pre><p>In particular: are you saying that falling through should be the default and <code>break</code> should be required to prevent it - as in C - or that falling through should never be allowed?</p></pre>winger_sendon: <pre><p>Are you asking me or <a href="/u/martingxx" rel="nofollow">/u/martingxx</a>?</p></pre>parenthephobia: <pre><p>Oh. <a href="/u/martingxx" rel="nofollow">/u/martingxx</a> :)</p></pre>martingxx: <pre><p>It&#39;s not that there&#39;s anything big wrong with it, just that it adds very little value. So little it&#39;s not worth having in the language.</p></pre>winger_sendon: <pre><p>So you replace switch which need fallthrough with if statements? Or go back to breaking every case?</p></pre>daenney: <pre><p>I&#39;m all for removing <code>new</code> but why drop <code>encoding/csv</code> and <code>database/sql</code>? Is there something fundamentally wrong with the implementations or do you think they should just not live in the standard library. And if so, why?</p></pre>martingxx: <pre><p>Nothing fundamental. I just think these things would flourish elsewhere, partly due to being able to have a very different release cycle from the standard library.</p></pre>Sythe2o0: <pre><p>Well, people are welcome to write their own handlers (and have) on top of or without the standard library&#39;s implementation, but they&#39;re very useful to have in the standard library.</p></pre>bupku5: <pre><p>a DB abstraction is necessary....but the one in the SDK isn&#39;t really adequate</p></pre>viiralvx: <pre><p>It&#39;s pretty adequate at our company and we got over a million users. To me it works out just fine.</p></pre>
42 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet