15 ms·
Why Go is elegant and makes my code elegant
- kyrra 13y agoSome of the pain points I've seen: * while "go get" is nice, it doesn't handle version pinning at all. So for a large team working on a go program, you need another solution. Luckily there are tools like godep[0] that will allow version pinning and putting it's source code into your projects root. * debuggers (gdb) are only partially supported. Most people don't have problems with this, but occasionally it's an issue. * Windows support is not as strong as Linux and OSX. But it still works surprisingly well. [0] https://github.com/tools/godep https://github.com/tools/godep
- mitchellh 13y agoA serious question (not saying you're wrong, I'm just genuinely curious): What issues have you run into with Go and Windows? I've been shipping libs and programs written in Go for Windows without issue.
- garfij 13y agoSometimes I wish debugging worked on Windows, but generally speaking I've found Go makes unit testing natural enough that it's not a big deal.
- jksmith 13y agoSame here. Good support in LiteIDE. Debugger works from LiteIDE. Been meaning to try this LightTable plugin (https://github.com/toqueteos/LightTable-Go https://github.com/toqueteos/LightTable-Go) but haven't gotten around to it yet.
- JoelHobson 13y agoHey, I'm one of the contributors for that plugin. There's still a lot of work to be done, but I'm finding it fairly usable right now. If you get around to it soon, make sure to grab the plugin from Github and not the plugin manager. The version in the manager is very out of date. And pull requests are very welcome. EDIT: For the record, I'm using it on Windows
- kyrra 13y agoAs for debugging, there were some comments about this recently on golang-nuts. A discussion about debugging[0]. Also Rob Pike saying GDB support is 'poor'[1] and there are bugs[2] that aren't a high priority to fix. Though, as many people pointed out on the mailing list, print statements and unit tests will cover 95% of your issues. As for windows support, I should say that it's really just as good as the gnu toolchain support is on windows. There is no support for using Microsoft's toolchain on Windows. It can also take some work to make go apps not run within cmd terminal. I saw a blog post about it recently but I can't find it right now. But it also mentions things like the syscall[3] library docs on golang.org are actually for Linux, and it takes some steps to get them for other platforms, see the header comment here[4]. So Windows support is pretty good, but it is definitely not Google's focus. But if you've ever heard about what Windows is like within Google, there is a good reason for that. [0] https://groups.google.com/forum/#!topic/golang-nuts/YG-APRPwkZc https://groups.google.com/forum/#!topic/golang-nuts/YG-APRPw... [1] https://groups.google.com/forum/#!msg/golang-nuts/DS5ZGswXC68/4kBgwVaAApYJ https://groups.google.com/forum/#!msg/golang-nuts/DS5ZGswXC6... [2]https://code.google.com/p/go/issues/list?can=2&q=label%3AGDB https://code.google.com/p/go/issues/list?can=2&q=label%3AGDB [3] http://golang.org/pkg/syscall/ http://golang.org/pkg/syscall/ [4] http://golang.org/src/pkg/syscall/syscall.go http://golang.org/src/pkg/syscall/syscall.go
- mitchellh 13y agoI still don't see any problems with Windows support here. Debugging is a problem, actually, but other than that everything seems fine. The syscall interface gives you access to call any Windows API you want. I wouldn't imagine writing a GUI app in Go, Go just isn't made for that and it would be silly since Microsoft's .NET tooling is so darn good. But Go for services and command line apps for Windows it has been fantastic.
- abtinf 13y agoGo on 32 bit Windows is a unreliable. I wrote about it some time ago[0]. I don't think it will ever be fixed. That said, I still use Go all the time. [0] http://www.abtinforouzandeh.com/2012/04/08/Do-Not-Use-Go-For-32bit-Development.html http://www.abtinforouzandeh.com/2012/04/08/Do-Not-Use-Go-For...
- jzelinskie 13y agoI think elegant is probably the wrong word. Practical is the one I would use. Go isn't Haskell; it isn't there to impress the PL guys. They boiled down the average imperative language and made many decisions for you so that opinions don't have to collide while working on a project. Because the decisions they made, they have very nice tooling to go along with the language.
- deleted 13y ago[deleted]
- 0xdeadbeefbabe 13y agoAs the project gets bigger the right word approaches "elegant" but practical does fit. It seems like a language for engineering software, big software like c++'s boost or google's bot. Unsurprisingly, bloggers aren't talking about that scale.
- chimeracoder 13y agoI agree completely. I like Lisp because it's elegant, and the solutions to difficult problems in Lisp are beautiful in every sense of the word. I like Go because it's practical. I can hammer out the solution to a difficult problem very quickly and that quick solution is reasonably scalable from a software engineering perspective[0]. Go makes it easy to write the first iteration, but its real strength comes from making it easy to write the subsequent n iterations. That's "elegance" of some sort, but it's elegance in engineering, not in programming, which is an important difference. You might say it's "elegantly practical" [0] By "scalable" I don't necessarily mean performance, but the costs of scaling developer manpower on large projects - ie, a "quick-and-dirty" solution in some languages may require expensive refactoring down the line, or cause you to design bad interfaces in your functions, etc.
- duaneb 13y agoI would go a step further and say it's not elegant so much as practical and simple. On large projects this can be confused for elegance.
- copergi 13y agoElegant is definitely the wrong word. Scheme is elegant. Go is simplistic. Not the same thing.
- lectrick 13y agoGo exception handling (or lack thereof) sucks. Things can just blow up silently at runtime unless you check the error code return of practically every statement.
- mitchellh 13y ago> unless you check the error return code of practically every statements Yes, you MUST. That is just how Go does things. If you don't do this, then of course things are going to blow up at runtime. Your "unless" is the same as saying in a language like Java: unless you rescue the exceptions, the program crashes! Yes, clearly. Personally, I love Go's error handling. I made a joking tweet one time that over 10% of all lines of code in Packer are "if err != nil". That is still probably true, but I don't think its a bad thing. We also make Serf, which is powering some pretty large infrastructures out there, and we've never ONCE had a crash in production. Not once. We've had errors, but they were logged and handled. I attribute this to the fact that we were forced to handle every error. Some people like exceptions, but I've always liked Go's way of things in this department.
- khyryk 13y agoIn my opinion, it should be a compile error to ignore return values without explicitly throwing them away with _.
- Dobbs 13y agoerrcheck will add this as an optional linter. I've adjusted the git hooks on my machine to run errcheck and fail the commit if it doesn't pass (unless I specifically disable it).
- aaronblohowiak 13y agoadd https://github.com/kisielk/errcheck https://github.com/kisielk/errcheck to your continuous integration process.
- lmm 13y agoIf 10% of your lines are repetitions of the same thing that's absolutely a problem with the language. You should find a more concise way to express the same thing (e.g. error monad).
- fireblade600RR 13y agointeresting..
- resu 13y agoHas the popularity of Go died off recently? This is the first Go article I've seen on the front page in a while...
- edwinnathaniel 13y agoWhen a programming language doesn't solve mass/common problems, its popularity will definitely decrease after initial peak. Rails solve common problems for the most popular platform: web. Go is created to replace C, a system programming language which could be considered as a niche. You see popular Go projects specifically addressing system level stuff (infrastructure: packer.io, docker, etc).
- newaccountfool 13y agoSurely systems programming is more popular than web? As you need a system to access the web, but not every system accesses the web...? What can I do in Rails that I can't do in PHP?
- Legion 13y ago> Surely systems programming is more popular than web? As you need a system to access the web, but not every system accesses the web...? "Systems programming" != "Systems software". Systems software is more widely used, but written by fewer people.
- rubiquity 13y agoSystems programming is further down the layers of abstraction than Web Development is. As you go deeper and deeper down these layers there are fewer and fewer people solving the problems that the layers above depend on.
- sehr 13y agoThere are more web developers on this site than systems developers. What can you do in PHP that you can't do in C, or assembly, or binary...
- 13y ago
- anonymoushn 13y agoOP has never heard of panic() and recover(), which are awful things that should not exist. I'll speculate that he hasn't used a language with a usable sum type either, because I'd expect people who have been exposed to this would take issue with the idea of expanding every 5 line method to 40 lines of mostly error handling.
- rubiquity 13y ago> OP has never heard of panic() and recover(), which are awful things that should not exist. OP is using panic in the Heartbleed script he wrote. Source highlighted here: https://github.com/FiloSottile/Heartbleed/blob/master/bleed/heartbleed.go#L33-L47 https://github.com/FiloSottile/Heartbleed/blob/master/bleed/...
- sdegutis 13y agoAh yes, very good examples of how Go's error handling needs improvement.
- NateDad 13y agoUh, no. You shouldn't use panic for error handling. You should basically never use panic unless you have some small bit of recursive algorithm inside your package that you want to be able to easily unwind. For general error handling you should only ever use error returns.
- FiloSottile 13y agoPlease consider that I wrote in a time measured better in minutes.
- rubiquity 13y agoI'm not criticizing your use of it, just showing the other person that you do know what panic is because you used it.
- FiloSottile 13y ago
- TylerE 13y agoIt's elegant right up until you need generics. Then it gets ugly fast.
- mitchellh 13y agoI agree you with you about generics, but downvoted you anyways, because "it gets ugly fast" is not true. I've certainly felt the pain of wanting generics for some data structures, but I've never felt the pain to where I've needed to make specialized structures for more than 2 or 3 types. And it had no real effect on the rest of my code. It was just one of those things where if I had generics, I could remove the 3x duplication of some code. It definitely doesn't ruin the language.
- khyryk 13y agoI want map (the function). I want filter. And I don't want to keep rewriting them over and over when I work on projects. They're not required -- indeed, I get by without them --, but the topic of the OP is elegance.
- mediocregopher 13y agoI wrote this to scratch an itch of mine: There is nothing about go which prevents the use of generics. I wrote the following library to scratch an itch of mine: https://github.com/mediocregopher/seq https://github.com/mediocregopher/seq It provides clojure-like data-structures and functions for interacting with them (like map and filter). It's completely immutable and generic, and supports lazy operations.
- steveklabnik 13y agoYes, if you totally throw away the type information, then Go will let you write some generic code. Your library uses a _ton_ of `interface{}`, because it has to.
- TylerE 13y agoPrecisely. Other languages, Nimrod for instance (http://nimrod-lang.org/system.html#515 http://nimrod-lang.org/system.html#515) can manage this while still keeping a simple core, including lots of type-inference. Having generics doesn't automatically turn your language into Java. The map operator in Nimrod has a definition that is clear and simple: proc map[T](data: var openarray[T]; op: proc (x: var T): S): seq[S]
- theseoafs 13y ago> If you write a package, it will have a name. A unique one. In all the universe. How does that work?
- robert_tweed 13y agoSame way it works in Java: by convention. You use the repository URL on e.g., github in the package name, so if that URL is unique then your package name is unique. It rather relies on the assumption that you do have one unique canonical URL associated with your package for this to work, but one of the things about go is that a lot of it is based on pragmatic assumptions that turn out to be true often enough that the edge cases don't matter. If you use go get, it can auto-download any such publicly hosted packages, which is a nice feature, especially as it can get the dependencies for you as well.
- mholt 13y agoThe fully-qualified package name, by convention, includes the web path to its repository, for example: `github.com/smartystreets/go-aws-auth` is unique.
- mediocregopher 13y agoBasically to install a dependency you do something like "go get github.com/mediocregopher/somelib", and the tool will fetch it and put in the appropriate spot on your GOPATH. So the universal name of your package is also the address the package is retrieved from. You COULD host the package multiple places and it wouldn't be true that it would be unique in the whole universe, but that's up to you.
- deleted 13y ago[deleted]
- 0xdeadbeefbabe 13y agoWhy the strong opinions about blocking? Go discourages, at least me, from doing non-blocking IO. I've heard that's a unix philosophy though. For example, io.Copy will block.
- jbooth 13y agoThere's a robust syscall package that you can use to do whatever you want. And, under the hood, all of their net.Conn types use non-blocking i/o combined with the goroutine scheduler. Basically, the philosophy is that rather than do it yourself, just write really simple blocking code using lots of really cheap goroutines, and the runtime non-blockifies it for you. If you really want nonblocking behavior, you can easily spin off a goroutine to do your i/o and then send on a channel or callback or whatever, and if you really want really nonblocking behavior, you can less easily use the syscall package to write your own conn type.
- chris_va 13y agoThe Author touches on a lot of nice points, but does not address some of the problems with using Go. Anecdotally, from using Go for a number of projects... As a rough approximation, I think Go's marginal return tops out at about 1000 lines of code. Past that point, syntactically it is hard to do abstraction (interfaces or generics). As a result, I use it for scripting but not for larger projects. What about you all?
- shurcooL 13y agoCompare: https://github.com/shurcooL/Conception-go https://github.com/shurcooL/Conception-go - Go, 7'500 lines https://github.com/shurcooL/Conception https://github.com/shurcooL/Conception - C++, 15'000 lines Which would you rather work with? You can look at the commit activity to see my preference.
- frowaway001 13y agoIf you are rewriting your original code in a new language and only get a 50% reduction, the new language clearly sucks.
- shurcooL 13y agoThey are not feature equivalent, so it's hard to compare directly. That said, excluding code reuse, to me Go feels like 75%-100% of verbosity of C++ without header files. Also, I don't agree with your statement. If it were true, it would mean every language clearly sucks.
- yohanatan 13y agoI think part of his point is that the mere re-write itself should save a huge chunk of that. Quite probably if you were to re-write it in the original language you could still get 25-30% decrease in code size (or more).
- frowaway001 13y ago
- wyager 13y agoThis may be an unpopular opinion, but I hope Go is relegated to web services programming. It's really not a good language for much else. The lack of generic support is really terrible. What you have to do instead (cast things to {}interface) is like casting things to Object and then hoping they have the right methods in Java. For everything else, I think Rust is miles better than Go. It stole a ton of useful features from Haskell/ML and did a great job of putting them together. I actually want to use Rust instead of C++, whereas the only reason I ever really want to use Go is that its decent threading primitives and good standard library make for simpler web apps.
- azth 13y agoThat's mainly the conclusion I came to as well. I find Go nice to use for writing web apps and services. For anything more complex/critical and/or with a high demand for correctness, I find using Rust to be a no-brainer compared to Go.
- copergi 13y ago>It's really not a good language for much else It isn't even good for that. There isn't a single use case where one of: D, ocaml, haskell, rust, or C isn't better than go. Go is the new java, a language that was inferior and obsolete when it was made. And like java, it'll probably be popular for a long time.
- NateDad 13y agoOne of Go's major features is that any particular function is very easy to reason about. The code is very straightforward, there's very little magic, and the code usually does exactly what you expect it to do, even if you're not an expert in the language. Rust seems nice, but its multitude of different pointers and mutable versus non-mutable data really makes for complicated code. I work on Juju. It's over 200k lines of code spanning several applications that coordinate across multiple machines. The number of times generics would have helped the codebase I can count on a single hand... and none of it is huge stuff, just some very minor parts of the code.
- wyager 13y ago
- vectorpush 13y agoI love go, and I concur with almost everything the author wrote here. A small pain point in my experience though is that Go lacks an elegant way to pass type information around without using a zero valued (or fully populated, it makes no difference) instance. For example, I have a factory struct with a New 'method' that returns interface{MySignatures()}, but I cannot inform the factory of the concrete type I want it to produce without passing in something like new(ConcreteStructWithMySignatures). Some have suggested I pass in a string, but what is the point of a type system if I have to use strings to reason about my types?
- melvinmt 13y agoYou're probably using Go in The Wrong Way®. It's hard to fit classical object oriented design patterns onto Go. A factory method that produces structs with dynamic types is an example of that.
- stcredzero 13y agoAgreed. For most of what you'd use a Factory Method for, you can Duck Type your way out of the situation.
- vectorpush 13y agoI created this contrived example to illustrate the basic idea behind the pattern I want to emulate. http://play.golang.org/p/7T2s8Dn0Sr http://play.golang.org/p/7T2s8Dn0Sr Ideally, on line 57 I'd pass in some kind of "first class" type representation that the switch statement could use to branch into the correct type, rather than a zeroed (or not, Go doesn't care) struct or a string. Admittedly, this could definitely be abuse of Go semantics, so I'm also interested in how I could refactor this into a more canonical Go pattern.
- melvinmt 13y agoWell, at line 57 you already know which provider you want to use, so why not just initialize the struct from there and skip the factory method altogether. http://play.golang.org/p/vXJcMJ-j6P http://play.golang.org/p/vXJcMJ-j6P Edit: I think I see what you're trying to do with the factory method. You're trying to enforce the ServiceProvider interface on every provider struct. You don't need to do that yourself, the compiler does that work for you. On line 57, you already know what kind of struct you're dealing with so you can safely call .connect() on the provider. And if you need to pass on the provider to another method, just make sure the method only accepts structs with a ServiceProvider interface. The compiler will stop you when it's not the case.
- cyphunk 13y agoone mans trash anothers treasure. When I pointed out that Django is an annoying framework because it breaks up your ability to prototype flat by forcing you into some workflow structure I was told "that's a feature". Go is similar. It's annoying but some people like bumps in the road. Enjoy
- mildtrepidation 13y agoIt's annoying but some people like bumps in the road. You apparently tried to build a prototype with a framework that very explicitly tries to provide more than just prototype capabilities. Invoking "one mans trash anothers treasure [big sic]" and then citing this is ridiculous; your failure to choose the right tool for your chosen task does not reflect poorly on the tool, nor does it suggest people who do use it correctly "like bumps in the road."
- cyphunk 12y agoI guess I wasn't clear and just letting out a bit of steam. Still doing it but to be clearer... Go feels more like a framework than a language. could be by design, but didn't expect it. also you are right, "bumps the road" is not fare. Better would be to say, in referring to myself, i guess you can't teach an old dog new tricks ;)
- iopq 13y ago> Go is compiled. This has a number of advantages, first being all the errors that can be detected by the compiler You can have static typing and type checking without compilation. The interpreter can just complain to you when you try to run it.
- Dewie 13y ago> The interpreter can just complain to you when you try to run it. That sounds more like strong dynamic typing.
- iopq 13y agoBut that's wrong. If I have strong dynamic typing and the program never goes to that part of the code, I don't get an error. What I'm talking about is more like Haskell repl. It will still complain if you muck things up when you type them into the repl. Dynamically.
- Dewie 13y ago> But that's wrong. If I have strong dynamic typing and the program never goes to that part of the code, I don't get an error. Exactly. > It will still complain if you muck things up when you type them into the repl. Dynamically. Yeah, because it's a REPL so it has to evaluate every line of code that you give it. How does that work when you have code as a file and you run the main function of that file? You would have to run every line of the code. So what about code paths that are not taken? Do you just give enough input data that eventually all code has been run through? But then you 're not really running the main function, you're running all the code of that program has, with whatever results and output that that might give. Obviously I'm not talking about Haskell here, which already has a static type system. Is your claim that you don't need a compiler to do type checking? Well, yeah, since type checking is not part of the source code translation. But it often said to be part of a compiler since it it often is often part of the semantic analysis phase. But if you have an interpreter you wouldn't really have a compiler as in a program translator. I interpreted 'The interpreter can just complain to you when you try to run it.' as "complain to you as you are running it". Not "complain right before you run it".
- al2o3cr 13y agoHaving uniquely-named packages is insufficient unless the maintainers of those packages never update them. The point of tools like Bundler is not about name resolution, it's about VERSION resolution. Sample size of 1, but here's a story about what happens when things go wrong: https://www.kickstarter.com/projects/2066438441/haunts-the-manse-macabre/posts https://www.kickstarter.com/projects/2066438441/haunts-the-m... The bit about packages from github.com being edited locally was particularly hair-raising. Really hope the smart folks working on Go figure out a resolution for this kind of thing.
- NateDad 13y agoThe bit about packages being edited locally shows the problem was between the chair and keyboard, not in the language. That's like making edits to some local files and never pushing them up into source control. Of course it'll never work outside your own local machine. There are practices and tools for insulating yourself from changes to third party packages. Generally the answer is to copy the code into your own repo so that you control when it gets updated. There are tools that will do this automatically for you, and it's what most big Go projects do.