When will a newbie suffer from the lack of generics.

xuanbao · · 494 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>In discussions about Go, the lack of generics usually comes up. As a newbie in Go, when is the typical situation where I will suffer from this?</p> <hr/>**评论:**<br/><br/>egonelbre: <pre><p>Read <a href="https://docs.google.com/document/d/1vrAy9gMpMoS3uaVphB32uVXX4pi-HnNjkMEgyAHX4N4/edit#heading=h.vuko0u3txoew" rel="nofollow">Summary of Go Generics Discussions </a>. It also lists places where those things might occur and also alternative solutions to those problems.</p></pre>aLikeA: <pre><p>Yea that&#39;s the correct answer I asked myself why another one was on the top for the last day. Noone cares about single opinions. In this document the arguments are clearly listed. And there&#39;s almost noone saying it&#39;s not required we all know we have to find a good way to implent them.</p> <p>However I think every newly started discussion regarding this is useless and the arguments are just repeated. Just follow the link and your question is answered. It highly depends what you are trying to archive.</p></pre>thockin: <pre><p>That doc is pretty bad. So many of the &#34;con&#34; statements are hypothetical. ...can be less efficient ...can be harder to understand.</p> <p>If the Go team wanted it they would invest in it. But Go comes from people who fundamentally dislike &#34;advanced&#34; languages and features, and so they won&#39;t.</p> <p>Accept that as truth and move on. Programming in Go is a much more pleasant experience once you stop hoping the core language will get significantly better.</p></pre>egonelbre: <pre><p>&#34;can be harder to understand&#34; --&gt; concrete things are processed more efficiently by the brain than abstract things. That of course ignores that you can write bad code with and without generics.</p> <p>&#34;can be less efficient&#34; - where did you find that? I found &#34;can be less optimized&#34; --&gt; concrete solutions can be optimized more, due to business/domain/context knowledge that is not available in the generic case.</p> <blockquote> <p>If the Go team wanted it they would invest in it. But Go comes from people who fundamentally dislike &#34;advanced&#34; languages and features, and so they won&#39;t.</p> </blockquote> <p>See the &#34;Addtional Comments&#34; section that contains Russ Cox. &#34;dislike&#34; is the wrong word.</p></pre>mc_hammerd: <pre><p>suppose you want to write a pop() function that pops the last element of a slice...</p> <pre><code>func pop(arr *T) { l := len(*arr)-1; val := (*arr)[l]; *arr = (*arr)[:l]; return val } </code></pre> <p>even though the same code can be used, theres no generics, so now you have to write 10 functions, or a switch statement to handle each type (20 lines?):</p> <ul> <li><code>popInt</code></li> <li><code>popInt8</code></li> <li><code>popInt16</code></li> <li><code>popInt64</code></li> <li><code>popFloat</code></li> <li><code>popFloat64</code></li> <li><code>popString</code></li> <li><code>popRune</code></li> <li><code>popByte</code></li> <li><code>popChar</code></li> </ul> <p>...etc</p></pre>TheMerovius: <pre><p>You always hear this answer, but… I have never seen a program that needs 10 different pop functions? If you need it, you only ever need it for one single type, <em>maybe</em> two.</p> <p>And even <em>if</em> you need it (you don&#39;t): You have to add 10 two-line functions. So what? That will hardly even come up on your radar even in time or in code.</p></pre>thockin: <pre><p>Ever written a program that needs 5 different kinds of slices? Recall that Go doesn&#39;t have a &#39;set&#39; type. I use sets all the time. We end up just using maps, and open-code all the set-related logic.</p> <p>Repeat this pattern a dozen times in a large program and I you might start to appreciate generics.</p></pre>TheMerovius: <pre><blockquote> <p>Repeat this pattern a dozen times in a large program and I you might start to appreciate generics.</p> </blockquote> <p>I <em>am</em> appreciating generics. I just can also live without them. They are not very important. And I think your set example is a perfect example for that, actually. It is next to zero additional work to just use a <code>map[T]bool</code>.</p> <p>And don&#39;t forget, that the large the program, the less the maybe 10 additional lines of code will really factor into it&#39;s complexity.</p></pre>thockin: <pre><p>Map is fine, unless you actually want set operations - union, intersection, etc. You have maybe 100 LoC per set type, and fixing bugs means touching them all. The only word for it is CLUMSY.</p></pre>calebdoxsey: <pre><p>I agree that generics would help with containers.</p> <p>One approach to this problem is to use <code>go:generate</code> for the type you need. I&#39;m not sure if someone&#39;s written a set version out there, but here&#39;s one for b trees: <a href="http://godoc.org/github.com/cznic/b" rel="nofollow">http://godoc.org/github.com/cznic/b</a>.</p> <p>If you needed 5 of these you could add 5 comments, run <code>go generate</code>, and get strongly typed sets. It&#39;s extra code, and writing the &#39;template&#39; is a little tricky, but it&#39;s not all that different from using something like protocol buffers.</p></pre>thockin: <pre><p>Generating is better, but I think the model of generate manually and check the results in is horrific. It&#39;s unfortunate that go:generate is not smart enough to do this work on demand. Even &#39;make&#39; gets this righter than go.</p></pre>TheMerovius: <pre><p>The idea behind generated code is, that you can <code>go get</code> it then and that you don&#39;t need third-party tools to build. It&#39;s a good idea, I think.</p></pre>ansible: <pre><p>You aren&#39;t going to suffer much. If you write generic code using <code>interface {}</code> then you will lose some type safety.</p> <p>If you are making a library of containers, you might want want to consider using code generation like with this utility:</p> <p><a href="https://clipperhouse.github.io/gen/" rel="nofollow">https://clipperhouse.github.io/gen/</a></p> <p>This will allow you to create containers (stacks, queues, whatever) and keep type safety.</p></pre>yene: <pre><p>You will find yourself re-implementing search an filter methods for every type. But this is not suffering, it just moves the implementation detail closer to your type, which is what you want.</p></pre>drunk_puppies: <pre><p>Go ahead. &#34;Rewrite&#34; the code for every implementation. Which actually means - cut and paste the code - search and replace the important bits - hope you didn&#39;t miss anything - repeat n times - find a bug - fix bug n minus c times, where c is the number of new people on your team times seven divided by the length in days of your sprint - find the same bug 1 week later in different scenario - fix bug n minus c times again, until you no longer work there or all code ceases to change. </p> <p>I&#39;ve been working with c# for the last year to program a video game and I love it. </p> <p>C# generics give you the ability to code the gears and guts of your program once, then write all the unique/custom functionality in a way that is succinct, obvious and extendable. Especially when generics are given constraints. </p> <p>In my opinion, anyone that says otherwise hasn&#39;t worked on a large code base that has many responsibilities and is frequently updated (like UI or evolving business logic), or puts way more trust in their grep tools than I do, or knows some voodoo that I haven&#39;t learned during 10 years of programming. </p> <p>And, because I know we&#39;re all in different places in out career, I have to say that generics aren&#39;t the solution to every problem. I prefer to code everything out explicitly first, then if I need to use a part of the code in three or more places - I find the bits that I would cut and paste and figure out a way to share that logic - usually using generics. Never start with generics. </p> <p>I&#39;d love to hear how go users implement features that combine generic and unique functionality. I&#39;m sure there are creative ways to do it, but so far haven&#39;t seen anything that would get c# programmers excited. </p> <p>Edit: egonelbre posted a great link outlining the arguments that apply to your question. That should get you started if you really want to understand this argument. </p></pre>TheMerovius: <pre><blockquote> <p>In my opinion, anyone that says otherwise hasn&#39;t worked on a large code base that has many responsibilities and is frequently updated (like UI or evolving business logic)</p> </blockquote> <p>You mean, like the People working at Google with a 76TB repository and tens of thousands of commits a day? I am sorry, but saying stuff like this is just… ridiculous.</p></pre>caseynashvegas: <pre><p>However, they don&#39;t use Go exclusively. I maintain that is it is true that some problems are easier to model in an object oriented language with generics, some are easier to model in a functional language and some are easier and perfectly valid to model in Go. That being said I believe <a href="/u/drunk_puppies" rel="nofollow">/u/drunk_puppies</a> could achieve the some of the same things he does with generics in C# by using interfaces in Go.<br/> Source: I&#39;ve been programming .Net since version 1.0 (pre-generics) and I&#39;ve been writing and loving Go code for about a year now.</p></pre>TheMerovius: <pre><blockquote> <p>However, they don&#39;t use Go exclusively.</p> </blockquote> <p>True, but they also don&#39;t use a lot of generics in <a href="https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Template_metaprogramming" rel="nofollow">languages that support them</a>. Thinking that working at scale necessitates generic programming is simply blind. And claiming that people who disagree with you just don&#39;t know their stuff and &#34;never worked on a large code base&#34; doubly so.</p> <blockquote> <p>I maintain that is it is true that some problems are easier to model in an object oriented language with generics</p> </blockquote> <p>True. I never said, generics aren&#39;t useful. Just, that their usefulness is grossly overstated (and <del>your</del> drunk_puppies post is a great example of that). Most real-world software can deal just fine without them. Yes, having a generic sort-library that just takes a cmp-function is more convenient to use than the go way of <a href="http://godoc.org/sort" rel="nofollow">sort</a>. But the go way only takes a handful of additional lines of code per type and you won&#39;t have enough types in your program that it becomes a major pain point.</p> <p>Literally <em>every</em> problem I have <em>ever</em> seen, that is &#34;easier modeled with generics&#34; came down to &#34;I want to write this generic algorithm&#34;. And yes, generic algorithms are by definition easier to model with generics. But the vast majority of cases can manage just fine with the less generic one.</p> <p>[edit] didn&#39;t look at usernames, stupid stuff :)</p></pre>ItsNotMineISwear: <pre><p>Linking an article about not using C++ template metaprogramming is extremely disingenuous to this discussion. That isn&#39;t analogous to Java/C# generics, which is what most people think and are referring to.</p></pre>TheMerovius: <pre><p>Maybe you can enlighten me then? I know C++ template metaprogramming and I know what Rust calls generics. They are the same. So… what is the difference?</p> <p>[edit] and btw: No, it&#39;s not. Because this was about Google&#39;s usage of generics. I can&#39;t say anything about Java, but I <em>can</em> say that Google doesn&#39;t use generics in C++, which <em>has</em> them, whether they are different from the C# ones or not. If they are not, that makes the argument <em>even stronger</em>, because it shows even more, that you can maintain a <em>large</em> codebase without generics.</p></pre>drunk_puppies: <pre><p>Yeah interfaces are great and I use them a lot, but they don&#39;t fix the cut and paste problem. </p></pre>TheMerovius: <pre><blockquote> <p>the cut and paste problem.</p> </blockquote> <p>But my point is specifically, that cut and paste <em>isn&#39;t</em> a problem. It takes 10 seconds. And adds 10 lines or so to a program with tens of thousands of lines, probably. And then it&#39;s done. It&#39;s only a problem, if you <em>define</em> it to be a problem.</p></pre>caseynashvegas: <pre><p>Cut and paste is definitely a problem, however repeating a pattern sometimes is okay. When the pattern is repeated enough, that&#39;s an ideal candidate for code generation which eliminates some of the pain and potential for human error. Adding a preprocessor to your build process isn&#39;t super onerous after all.</p></pre>drunk_puppies: <pre><p>Good point. I was trying to differentiate between a script that processes a request or evaluates a file and a more nuanced application like a game or a web experience. Also, I always thought go was supposed to replace all of google&#39;s c code - which would have been used for the former and not the latter. </p></pre>TheMerovius: <pre><blockquote> <p>Also, I always thought go was supposed to replace all of google&#39;s c code</p> </blockquote> <p>It wasn&#39;t, really :) That&#39;s far too much code to ever be replaced :)</p></pre>thockin: <pre><p>Yeah, we mostly use C++</p></pre>TheMerovius: <pre><p>Without generics.</p></pre>thockin: <pre><p>Umm, nope. Tons of templates and generic code in Google. Tons.</p></pre>yene: <pre><p>?</p></pre>Ainar-G: <pre><p>This will most probably hit you first when you&#39;ll try to &#34;compress&#34; for-loops into functions à la <code>fmap</code> or <code>filter</code> when working with collections. In Go today you can either create such functions for one concrete type, or create a function that works on <code>interface{}</code>s and thus works slower. In e.g. Ruby you would do something like</p> <pre><code>filtered = collection.map(&amp;:method1).filter { |thing| thing.method2?(foo) } </code></pre> <p>while in Go this will be more like</p> <pre><code>filtered := make([]thing, 0, len(collection) for _, t := range collection { t.method1() if t.method2(foo) { filtered = append(filtered, t) } } </code></pre> <p>unless you write <code>fmap</code> and <code>filter</code> for <code>thing</code> type or use something like <a href="https://github.com/robpike/filter" rel="nofollow">Rob Pike&#39;s filter package</a>. I would personally recommend just factoring such loops out if they are needed in the code more than once. So that you could just write</p> <pre><code>filtered := filterThingsCollection(collection) </code></pre></pre>TheMerovius: <pre><p>From what I saw: Newbies suffer from the lack of generics, because they have their usage of the language somewhat backwards.</p> <p>New people often come to go, they want to have an impact on the community, instead of using the language for real projects. To have an impact on the community, they will try to satisfy some perceived need. The simplest way to fill a perceived need, is to write a package. They very soon come to the conclusion, that what the go community <em>really</em> needs (because, well, it doesn&#39;t exist so far) is a generic max/min, a filter function, a generic range, a map-function… And to solve this perceived community need as generally as possible, they want generics.</p> <p>But this is getting everything wrong. The community <em>doesn&#39;t</em> really need these things. It would be useful, sure, but oh well, it&#39;s such a minor itch, it will only need a couple of lines of obvious code anyway and there are far more important things that are far easier to solve and don&#39;t need this generality.</p> <p>So, generics are a pain, mainly for new coders who</p> <ul> <li>Want to have an impact on the community</li> <li>Perceive a problem in the lack of some package</li> <li>Want to contribute this package to the community in the most general way possible.</li> </ul> <p>Generics won&#39;t bite you, if you just… write some real programs. If you want to contribute, write great tools, instead of generic libraries.</p></pre>brogrammingsins: <pre><p>When they start asking for/about them</p></pre>pierrrre: <pre><p>When you try to create a generic library instead of getting shit done.</p></pre>TheMerovius: <pre><p>I think this is entirely the problem, even though you phrased it not very good :)</p></pre>pierrrre: <pre><p>Yes, your answer is better. But I like short answer :)</p></pre>Ainar-G: <pre><p>I don&#39;t think that it&#39;s a productive attitude. </p></pre>barsonme: <pre><p>I kind of do. Generics have their place, and maybe in the future that will be in Go or a fork of Go, but until then why waste your time trying to bend Go into something it&#39;s not?</p> <p>When all you have is a hammer... blah blah blah.</p></pre>postman_: <pre><p>With this mindset all you will be getting done is truly only shit.</p></pre>drvd: <pre><p>Never. Not even non-newbies <em>suffer</em> from not having generics.</p></pre>TurquoiseTurkey: <pre><blockquote> <p>In discussions about Go, the lack of generics usually comes up.</p> </blockquote> <p>In tedious discussions about Go on net forums, some tiresome individuals drone on and on about generics, then they tell you to use Rust instead. They&#39;re called &#34;bores&#34;.</p></pre>Blobqx: <pre><p>I doubt any person with a decent knowledge about rust and go would say this. It was often clarified rust and go are in no way competitors.</p> <p>I am very happy to use both and alot of people would say so aswell.</p></pre>TheMerovius: <pre><blockquote> <p>I doubt any person with a decent knowledge about rust and go would say this. It was often clarified rust and go are in no way competitors.</p> </blockquote> <p>Really? <a href="https://www.youtube.com/watch?v=BBbv1ej0fFo" rel="nofollow">At this panel</a> it indeed <em>did</em> sound to me like the rust person is trying to argue, that rust is at least <em>meant</em> to solve a large part of go&#39;s problem domain. [edit] and likewise, of course, rob argues that go <em>can</em> indeed occupy some of the domains people think only rust can handle [/edit]</p> <p>I agree that it doesn&#39;t and that it&#39;s not equivalent and I am careful which of the two to recommend to people when they ask, but it <em>does</em> look to me like rust and go are supposed to at least to a large degree overlap in their domain.</p></pre>Blobqx: <pre><p>Ofcourse there are always overlapping domains. I can only talk for me as person I use golang for mostly all network development. Go has alot predecided decisions, but all of them make it really good for network development. 9/10 times I would choose go for a network project because It&#39;s really nice to work with it.</p> <p>However Rust gives you alot of freedom. While the syntax may look abit weird you are still kinda free in your decisions. And most concepts in rust are really good in performance terms. While I use rust rarely mostly if I do some uni stuff or code some application which basicly is more functional on It&#39;s own and doesnt aim for serve/recieve any data. I think rust could contribute a significant change to the whole game development section.</p> <p>So I think Rust and Go will be able to keep important domains for theirself.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

494 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传