37 ms·
Go is not an easy language
- SEJeff 6y agoFWIW, the generics proposal was accepted: https://github.com/golang/go/issues/43651 https://github.com/golang/go/issues/43651 This will make a generic "slices" package much more trivial to write.
- CameronNemo 6y agoError checking/handling is still a pain. Maybe generics will make that easier? Result type when?
- tptacek 6y agoHow does a Result type making error handling easier? More reliable, sure, I buy that. But I write a bit of Rust these days, and error handling is definitely not easier. It's actually kind of an enormous pain in the ass, and it certainly seems to involve more lines of code than it does in Go (not just in my code, but in all the libraries I've read).
- jjnoakes 6y agoI've not had that problem. I would love to see the question mark operator in go because I think it is an elegant way to avoid a ton of boilerplate while still remaining a tad explicit about where errors can occur.
- lmm 6y agoThe most common thing you want to do with an error is bubble it up. IME Result types strike the least-bad compromise between making that too intrusive (if err != nil clutter) and making it too subtle (exceptions i.e. magic invisible control flow). (I don't think Rust is the best example of result types; it's missing a lot of tools for working with them because Rust doesn't have HKT and functions aren't quite first-class because of their lifetime checker, so instead of using ordinary functions you end up using ad-hoc macros or language special cases like ?. Since Go is garbage collected they wouldn't have that problem)
- CameronNemo 6y agoEasier in that I don't have to force my team to use a static analysis tool just so people don't silently ignore errors. CI works, but I have to set it up. For every project. And fix anything that was not developed with golangci-lint.
- ampdepolymerase 6y agoHasn't there been several error handling proposals already?
- kyrra 6y agoYes, and all have been rejected thus far. Finding the right balance for those things seems to be hard. See: Problem statement: https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md https://go.googlesource.com/proposal/+/master/design/go2draf... Proposal one: https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling.md https://go.googlesource.com/proposal/+/master/design/go2draf... Proposal two: https://go.googlesource.com/proposal/+/master/design/32437-try-builtin.md https://go.googlesource.com/proposal/+/master/design/32437-t...
- Pxtl 6y agoFinally! I honestly think that any statically-typed language without some minimal facility for generics - even C macros will do - isn't fit for purpose. I used Java and C# before the generics were introduced and you can't pay me enough to go back to that.
- benhoyt 6y agoI think the reason Go is usable compared to early Java is because it does have generics for the builtin types -- slices (growable arrays), maps, and channels -- and for the builtin functions that operate on these types. And you can get really far with just slices and maps (which double as sets). You just can't add your own generic types or functions.
- harikb 6y agoGoing by their first example, the fact that I couldn't write list.delete(value) without realizing it involves a linear search is considered one of the benefits of Go. That said, I agree Go could use a bit for ergonomic and handy methods, while still remaining efficient. The example on Concurrency also has a different answer. Go gives you all the tools, but there are many different ways their problem can be solved. By explicitly avoiding a "join" method and having any default 'channels', Go makes all these possible. What is missing is some of the popular patterns that emerged in the last few years need to make it to into stdlib or some cookbooks. 1. If you want a worker model, I would start n=3 go-routines and they all receive from a single channel. They don't need to much around with a channel of buffer 3, as in the example. 2. If the workers already return data from a compute, the read from driver serves as the wait. 3. In other cases, there is sync.Waitgroup available to synchronize completion status. 4. End of work from the driver can be indicated via a channel close. Closed channels can still be read from until they are empty and the reader can even detect end-of-channel. Designing concurrent system is a bit complicated. Some tutorials do make it sound like a `go` keyword is all you need. All of these can fixed by improving std-lib or cookbooks.
- prepperdev 6y agoYes. That very example shows why itis hard to write fast program in Ruby. It's not even the interpreter (which is slow), but it's that Ruby is pure magic. I was never able to understand what happens, when I looked at a particular snippet of Ruby code, if it was not me who wrote it. With Go, understanding others people code is a trivial task.
- nobleach 6y agoAs much as I don't personally enjoy writing Go. This is a huge benefit. There's a decent amount of conformity around the "right way" of doing things. I'll admit, it has definitely made me consider my approach to solving problems in other languages much simpler. I'm not back to writing loops in JavaScript when I use it. It really bugs the functional programming folks but... no one can argue that it's readable, and it's pretty fast.
- 6y ago
- systemvoltage 6y agoI want compiled Python with strong types. All the batteries of Python included. And runs at C speed. Go feels like C and Python had a baby except the baby looks more like C and less like Python.
- mberning 6y agoMany people just don’t understand the joy of working with something like python or ruby. Maybe they haven’t had an immersive experience with an “a ha!” moment. Coming from basic and similar languages to java, then later to jruby and ruby, and now back to java I have to say it depresses me how much more I enjoy some languages and technologies over others. I wish I could feel equally excited and happy to work in them.
- systemvoltage 6y ago100%, being productive is addicting and fun. Laboring through for-loops 80th time in a the day is something for sadist purists, not me. As a non-expert at Go, I would have loved classic OOP + batteries included Python and remove the curly braces. Perfect.
- pid_0 6y agoThis might be wrong but can't you use cython and then compile python to speed it up? Obviously won't be as fast as Go but seems like it can have speed ups
- cb321 6y agoIf you think of Cython as a "new but related" language rather than just a Py compiler then you can sprinkle enough C-like `cdef` code into your Cython so that, when compiled, your code can run much faster than Go..as fast as any C, really. (EDIT: Pypy is usually a better way to make unadorned Python run faster.) That said Nim [1] provides nicer metaprogramming features than Cython and very nice overall ergonomics..I think more ergonomic than Python with, e.g. UFCS. Nim has almost all the safety/speed of Rust with better ergonomics than Python. What is not to love? [1] https://nim-lang.org/ https://nim-lang.org/
- nitinreddy88 6y agoIn my opinion, coming from Java,C# background and currently working on golang, here's my take. 1. Golang did right design in terms of OOP 2. They didnt complicate the language by accepting everything. 3. At the same time, they made simple things so complex. Simple logics to removing an element from slice/array and even iterating them without screwing up the data. I have been programming for 10yrs and I find myself doing those mistakes without proper IDE/golint, while I can easily code in other languages without much help. I can concentrate on solving the business problem rather than fiddling around the language
- ironmagma 6y ago“Everything should be made as simple as possible, but no simpler.” I’ve often felt Go went too far trying to make everything simple, to the point that it’s wrapped around and made things complex.
- avmich 6y ago"Civilization advances by extending the number of important operations which we can perform without thinking of them." --Alfred North Whitehead Go forces writing loop for removing an element from an array even if the programmer knows it's linear time. Ruby gambles that programmer isn't ignorant - or it's not critical - but allows the convenience every time. Designing languages is hard.
- cratermoon 6y ago> Go forces writing loop for removing an element from an array It does not: copy(a[i:], a[i+1:]) // Shift a[i+1:] left one index. a[len(a)-1] = "" // Erase last element (write zero value). a = a[:len(a)-1]
- z0r 6y agoyou are right that a loop isn't required, but the point that kind of index / array element juggling is a headache still stands
- pid_0 6y agoYeah I agree with this. Go is awesome but pretty complicated. Channels still break my brain every time I use them.
- deleted 6y ago[deleted]
- taeric 6y agoConversely, I think go can be pushed as an easy language. In large, whether a language is "easy" seems dominated by perception. That is, most things that are "hard" have a reputation as being hard by non practitioners. Which isn't to say that empirically it is clear some languages make some errors easier to make.
- tptacek 6y agoI don't think that the claim has ever been that Go is especially easy to program in; it's about as good as any other mainstream language for expressing logic. It's that Go is simple enough that the language gets out of your way really quickly. I think the article kind of got the idea midway through, at "I think most programmers can figure out what the above does even without prior Go experience". Yes. That's the idea.
- hombre_fatal 6y agoI think anyone can agree with the author that Go definitely lacks conveniences you're used to in other modern languages. I just think we also tend to dramatize how much that matters. I also think Go's benefit really is that it's simple and that you have very few tools that let you do anything other than focusing on solving your problem, and like the author I do think goroutines are the exception to that. Where I work, we don't even use them. We use plain ol' mutexes instead. When coming from higher level languages, Go does feel frustrating. In Javascript, you're writing `const [a, b, c] = await Promise.all([x(), y(), z()])`. In Go, you're writing 40 lines of WaitGroup code. It's easy to go ughhh. But I think a nice way to appreciate Go's conservative middleground is to go back to writing some C/C++ code for a while, like some Arduino projects. Coming from that direction, Go feels like a nice incremental improvement that doesn't try to do too much (with perhaps the exception of goroutines). Go's performance is also particularly stand-out which makes up for many of its convenience shortcomings. It's fast enough that I've written some code in Go where I would have written C not long ago. And writing C involves quite a bit more concessions than what Go gives you, so in comparison, Go kinda spoils you. Go has plenty of annoyances too though. Not having any dev vs prod build distinction is annoying. Giving maps a runtime penalty of random iteration in order just to punish devs who don't read docs is annoying. It's annoying to have crappy implementations of things like html templating in the stdlib which steal thunder from better 3rd party libs. Not being able to shadow vars is annoying. `val, err :=` vs `val, err =` is annoying when it swivels on whether `err` has been assigned yet or not, a footgun related to the inability to shadow vars. etc. etc. But it's too easy to overdramatize things.
- strken 6y agoGo's lack of generics and metaprogramming can be extremely frustrating when you're working with services that copy data around from one struct to another, which ends up being a lot of them. You're left with reflection, code generation, or doing it field by field. It'd be nice to have syntactic sugar for splatting structs together, or a library that let you do it in a typesafe and efficient way. EDIT: I will defend the random map order, though. Golang maps were only predictable up until a set number of items, which caused hard-to-detect bugs where your small test case would be in order but your large real-life data would be out of order.
- q845712 6y agoAgree, agree, agree. I've bounced between Python, C++, and Rails in my career, and lately have been ramping up at a Go shop. Go is like C++ in the sense I can tell that eventually I'll get better at eyeballing a file, sensing the shape of the code, and zeroing in on the important bits. Just like learning to read large C++ codebases, there's clearly a learning curve because a simple idea that would be a one-liner in a high level language is going to be 5-15 lines. Go also makes the "learn to read" learning curve even steeper when folks pick up and propagate the core team's propensity for single letter variables. I feel like one of the understated benefits of ruby/python/similar languages being relatively readable is that folks are inclined to keep them readable. Whereas when you feel like you're one step away from specifying the register and how hot the welding torch should be to toggle the bits, you're somehow more likely to write `c.T.Client.Send(v)`. IMO if we accept that most of our work is maintenance & modification of existing code, and most of the work in those tasks is understanding what's already been written, it follows immediately that code that's easy to read has high business value. I know it's too soon in my learning curve, but I'm really hoping I find the patterns that make Go easy to read soon. (and a little tangentially but the descriptive power of a variable name should be proportional to its scope - so imo anything exported or that I might see across multiple files is an awfully strong contender for a multi-word descriptive name.)
- benjaminjosephw 6y agoLearning code shapes and conventions as a skill is definitely an important approach for the pragmatic programmer. Ultimately though, isn't this a necessary consequence of just not having a high enough level of abstraction in our programming languages? Here's my very opinionated view: in scenarios where maintainability and readability are the most important long-term characteristics of a program then the best programming language would be one which separated out the specification of a program's intent from its implementation. Separating concerns is a design pattern that we've learnt is really important (remember the early days of PHP?). We currently encapsulate logic around reasons for that code to change because we recognize the value of that pattern. Extending that same design pattern to what we know about the long-term maintainability of code means that we should be abstracting intent from implementation to allow both to change independently. Compilers and virtual machines already do some optimizations to this effect at the moment but we could go way further in our programming languages themselves. I think this means that declarative programming is the logical evolution of software design (really hope someone has an intelligent counter argument here because I can't see any myself). Go makes a great implementation language in this sense (Rust too) but it's bound to loose ground in the application space as soon as we find the right high-level declarative language to describe application software.
- parhamn 6y agoMost of these will be solved with the recently approve generics. Concurrency (less the pattern libs that generics will provide) feels generally hard. Although channel semantics in Go are very annoying (e.g what happens when you close a buffered channel). This is hard in most languages I’ve used. Anyone have an example of what the state of the art hard-to-shoot-yourself-in-the-foot concurrency looks like in another language?
- cutler 6y agoClojure's core/async and Elixir's actors.
- endisneigh 6y agoI really like Go, but I'd love something like JavaScript that had the performance of C^. If and when that happens there really wouldn't be any need for other programming languages IMHO. Oh well - that being said Go is way simpler than C++18 that I've done a tiny bit of work in. I think the issue is that Go generally competes with Ruby/Python/JavaScript in certain scenarios and just seems way more complex in comparison. If you compare Go with C++/Java/C# it seems more reasonable and "easy." ^ the good news is that a ton of money is being spent to improve Node performance - whether it'll approach Java/C++ speed is TBD, but the performance gap is shrinking year by year.
- vitus 6y ago> C++18 (Out of curiosity, is this C++17 or C++20? I'd assume 17, and also I'm curious which aspects you find confusing.) Several coworkers have remarked that it's just easier to reason about correctness of concurrent code in Go vs. C++, while not sacrificing performance as in, say, Python. (There's definitely a performance hit, per the use of a garbage collector.) One thing that's always bothered me about Go is just the things that are missing from the standard library; I think that contributes significantly to it being "harder" to work with. (A good number of these likely stem from the lack of generics, e.g. max(a, b int) int -- math.Max takes and returns floats.) That said, the biggest thing I liked about Go from the first day I used it was the treatment of concurrency as a first-class citizen (goroutines, channels).
- jpgvm 6y agoI would try Kotlin. Syntactically it's even more terse than JS and is as fast for most use cases as C. Main downsides are memory usage and needing to understand JVM limitations for latency sensitive codebases (TLDR: Use a modern JVM and ZGC or Shenandoah).
- thu2111 6y agoNote that with SubstrateVM/Graal native image, you get far lower memory usage and startup time equal to or even better than C.
- throwaway189262 6y ago
- nerdbaggy 6y agoIn Go tutorials I almost never see anything about mutexes or how to be thread safe
- strken 6y agoGenerally the answer is to stick everything into a channel. This doesn't fix race conditions, but it does make it easier to write code. Want to query the db in parallel? Start n goroutines and write the results to a channel, then read from the channel n times. Want to limit your concurrency to m tasks? Start m goroutines reading tasks from a tasks channel and pushing results to a results channel, write n tasks to the tasks channel, read n results from the results channel.
- eknkc 6y agoI find the channels to be the most confusing thing in Go. What happens when you write to a closed channel? What about a blocked one? What if you read from a closed one. Can you close a closed channel? Does that panic? What was the non blocking read? What about write? Fuck that, I use the sync Mutex primitives and good old slices instead.
- Groxx 6y ago+1 to this. I'd say nearly half of the channel code I've encountered in "real code" has had severe flaws when things don't align perfectly. They don't have data races, in that the race detector will give it a thumbs-up, but they do have semantic races leading to deadlocks, misbehavior, dropped data, etc. They generally work fine when they're not under heavy load / contention, so they aren't noticed until they collapse. Mutex code though? 90% correct, easily. It's often dramatically simpler to make correct, especially when more than one construct is needed, or nearly anywhere with error handling. (`defer` is quite nice for locks)
- lanstin 6y agoCause you need not worry about the threading if you are using channels and go routines. The scheduler does it all f9r you - you just describe the data flow and the concurrency.
- chmod775 6y agoWe're comparing (linked-) lists with arrays and compiled languages with scripting languages now? Why would you use an array/slice instead of a linked list, but then want to use it like a linked list? If you need a linked list, use something like this: https://golang.org/pkg/container/list/ https://golang.org/pkg/container/list/
- deleted 6y ago[deleted]
- unscaled 6y agoI think Go can only be defined as "simple" in the New Jersey (worse is better) sense of simple, that is: "it is more important for the implementation to be simple than the interface." A lot of things about Go are not simple. In my opinion a simple language is not about how simple it is to write a parser or a compiler for that language, but it's about how many different non-trivial and arbitrary pieces of information the developer has to memorize. This is highly tied to the Principle of Least Astonishment[1] in language design: how many unexpected surprises does the programmer have to deal with? With Go, you get quite a lot: 1. Go already has generic types. These are the magical maps, slices and channels. Everything else is not. 2. Even if you think #1 was also true for Arrays in Java 1.4 and no one was complaining, Go goes further: it already has generic functions like 'copy', 'len', 'min' and 'append'. Since you cannot properly describe the interface of a magic built-in function like 'append' using the Go language itself, this is not a standard library function, but should be viewed as an entirely new piece of custom syntax, like the print statement in Python 2.x. 3. Nil interfaces and interfaces with a nil pointer are not equal. 4. Multiple return values are a magical beast - they are not tuples and you cannot manipulate them in any useful way. 5. Channel axioms[2]. Possibly one of the more astonishing and painful aspects of Go. 5. Slices are mutable, unless you copy them. This can lead to some very surprising cases where a slice is passed down many layers below and then modified, breaking the caller. 6. Continuing the topic above, Go has neither clear data ownership rules (like Rust), clear documentation tradition on who owns the data passed to functions (like C/C++) nor a way to enforce immutability/constness (like C++, Rust or FP languages). This really pushes a lot of the cognitive overload to the developer. 7. Go modules are a lot better than what we had before, but are quite hard to deal with. The moment you need to move to v2 and above and start creating subdirectories they becomes rather confusing compared to what you would do in other package management system. 8. If a simple language is a language that allows you to write _simple programs_, and you follow Rich Hickey's classic definition of Simple[3], then Go is probably one of the LEAST simple languages available today. tl;dr: I'm not saying other languages often compared to Go (like Rust or Java) don't have their own share of complexities, but I don't think Go should be viewed as a simple language in the broadest sense. It is a language with a rather simple implementation for our day and age (though Pascal was much simpler if we stretch this definition backwards). [1] https://wiki.c2.com/?PrincipleOfLeastAstonishment https://wiki.c2.com/?PrincipleOfLeastAstonishment [2] https://dave.cheney.net/2014/03/19/channel-axioms https://dave.cheney.net/2014/03/19/channel-axioms [3] https://www.infoq.com/presentations/Simple-Made-Easy/ https://www.infoq.com/presentations/Simple-Made-Easy/
- tengbretson 6y agoThis is all just crazy to me. I cannot even remember the last time I dealt with array indices directly.
- soheil 6y agoThe fact that Go supports channels, buffers and workers means it's very much tailored to parallel processing. I always thought of it as a soft of worker farm except it's running on a single machine. You can run it in a multi-node environments as well, of course. I find the parallelism feature of Go so powerful that it overshadows its other features. For server side there are already many really well designed systems that allow for parallelism, Apache, Nginx, Kubernetes, RabbitMq... For client side parallelism maybe useful in things like games but even then there are frameworks better suited to take advantage of parallelism offered by GPUs. I like Go for command line apps, it's a much faster alternative to Python.
- cwojno 6y agoI agree with the author that Go is not as easy as Python or Ruby. However, the first example given is bad. Running delete on a slice is the same as trying to delete an element of an array. It's the wrong data structure if you need that type of access pattern. That's why it's hard. You can cut a tree down with a hammer, but it's going to take a while and you're going to have some blisters. Go has built-in linked lists. https://golang.org/pkg/container/list/ https://golang.org/pkg/container/list/ and I will agree, they're not as easy to use as other languages due to the lack of generics in go, at present. Using the list.* package requires type conversion to evaluate and pull values out of the structure. I think it's fair to say that Go needs to do a better job explaining the list package or possibly including it in the "Tour of Go" guide. That might help avoid these misconceptions in the future.
- jrpt 6y agoI feel like the majority of the time you just have arrays or slices of a manageable size, say <= 25 elements, and you just want to delete an element from it. You don't care about performance because it'll be fast regardless and surely not the bottleneck of your program. In my experience with Go, a lot of basic functionality is missing and requires you to write your own utility functions. And some things you would expect like mySlice.append(elem) are instead written mySlice = append(mySlice, elem) which isn't as elegant. Plus you have to remember it's not just append(mySlice, elem) If there's a handful of open source utility function libraries, that will split the Go developer base, kind of like how you used to have both jQuery, Prototype.js, underscore.js and others in Javascript. They should have just standardized all the common functionality you'd want and in an intuitive way.
- mrmonkeyman 6y agoPeople say things like "plumbing" and "utility" functions like their code consists of something more, something more meaningful. In Go, there is plumbing, everything is plumbing because that is what your job is. It makes it clear and boring. No fun I agree, but engineering is no fun.
- kaba0 6y ago
- mraza007 6y agoAfter reading this article now I’m questioning my self should i continue learning Go as this is giving me second thoughts that if it’s going to be useful for me to learn go
- arp242 6y agoI could write a "ugh, this is kinda annoying"-criticism of any language I've ever used in depth. I certainly didn't intend this to be a "Go sucks!" kind of post: as the author of this article, I still use (and like!) Go very much, and is pretty much the language I use by default for most problems. And even if it turns out you don't really like Go: that's okay. The only way for yourself is to actually learn it, and you will be more knowledgable and experienced regardless.
- thayne 6y agoAs someone without a ton of experience with Go, a good amount the Go code I have encountered "in the wild", has actually been more difficult to read and understand than code in more complicated languages because I have to read through and understand all of these patterns. Hopefully the addition of generics will help with that. But IMO the simplicity of go actually hinders readability.
- philosopher1234 6y agoCould you share an example?
- gher-shyu3i 6y agoNot the poster you're responding to, but practically every time someone wants to write code that mimics `map` or `filter` and gang is a 5-7 line function (at least). Something that would have been a 1 liner in languages like Java or C#. It gets tiring and distracting very quickly to jump around verbose implementations which amount to nothing more than standard streaming functions. Another example is the lack of annotations for validations. In Java or C#, you'd annotate the function argument with something like `@Validated`, and it's taken care of. In golang, calling the validation code would have to be done manually each time that's another 3-4 lines (including error handling). Yet another example is that golang lacks a construct similar to C#'s `Task`. You can't execute a function that returns a value asynchronously (if you care about that value) without creating a channel and passing it. golang also lacks pattern matching and discriminated unions (aka algebraic data types). Java and C# are getting both (both have pattern matching, and ADTs are in the works as far as I'm aware).
- fileeditview 6y agoHave to agree with you. I wished for sum types & pattern matching more than for generics.. but who knows what the future brings.
- cy_hauser 6y ago
- pansa2 6y ago> Go is not an easy programming language. It is simple in many ways This, exactly. It’s worth contrasting this with Python, which has a reputation for being simple but is actually extremely complex - but it is easy (at least for small programs). However, I can’t help thinking that the two shouldn’t be in opposition. IMO it should be possible for a language to be both simple and easy to use.
- vinger 6y agoMeet php.
- fmakunbound 6y agohttps://github.com/golang/go/wiki/SliceTricks https://github.com/golang/go/wiki/SliceTricks I was reading through this, which was referenced from the article. This just seems insane. None of any of that seems intuitive.
- cutler 6y agoMe too. Made me realise I picked the wrong language just for a performance boost. The Go patterns mentioned earlier are even worse.
- Measter 6y agoMeanwhile, in the much more complicated Rust, all but four of those are one-liners[0]. The exceptions being: * Expand. Rust doesn't provide an easy way to insert multiple values into the middle of a vector, so I had to do 2 lines: append, then rotate right a subslice starting at the desired insertion point by the length of the insertion. * Shuffle. No RNG in Rust's stdlib, so I used Rand. I did re-implement the shuffle, but in reality I'd probably just use the shuffle function provided by Rand. * In place dedup. Needed two lines: one to sort, then I could call dedup. * Move to front. This is not a function Rust provides, so it's completely implemented. Needed 10 lines. This one needs to search for the item and move that if it exists. In the event it exists, I rotate it left onto the end of the vector, then rotate the entire vector right. Otherwise it inserts at the beginning. [0] https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7fed5e30b0d4fab58f9231df19b4a46f https://play.rust-lang.org/?version=stable&mode=debug&editio...
- Dr_Emann 6y agoExpand does actually exist in the standard library, but it's a bit of a strange incantation... vec.splice(i..i, std::iter::repeat(0).take(length)); This replaces the values in range `i..i` (an empty range starting at i) with `length` copies of `0`.
- Measter 6y agoThat's not exactly the same. Splice returns an iterator, it doesn't modify the collection in place.
- deleted 6y ago[deleted]
- grodes 6y agoI hope this will change with generics, and we will get > slices.delete(slice, index)
- Philip-J-Fry 6y agoBut no one said Go was easy. It's just simple and easy to reason about. There's a huge benefit to something doing exactly what it says. No hidden behaviours, no overly complex syntax, nothing like that. I came from C# where I have gotten increasingly frustrated with the amount of additions to the language. Like we now have classes, structs and records. We now have async/await but we also have channels. This is what having a huge toolbox causes. Some people are going to write code using channels, me others will use async. Some people will use features that others don't care about. I think there's huge benefit in a simple language. In Go I know that there's only 2 ways to do concurrency. You either use go routines and mutexes or you use go routines and channels. Generics will bring a lot of helper functions that weren't possible before which will remove a lot of repetitive code. But otherwise I am super happy with writing Go code. All my pet peeves of something like modern Java or C# are gone.
- thayne 6y ago> But no one said Go was easy. Lot's of people have said go is easy. In particular that go code is "easy to read" is an oft-cited benefit of go. Also, if you go to golang.org and the first thing you see is: > Go is an open source programming language that makes it easy to build simple, reliable, and efficient software. (emphasis mine)
- Philip-J-Fry 6y agoGo is easy != easy to read. I personally do think Go is easy to read. The fact that I don't get bitten in the ass by hidden behaviours and there's no inheritance to step through 5 files of. The fact that everyone's Go code looks more or less the same (unless you're an absolute beginnner) because there's only so many ways to do something. Compared to C# where reading someone else's code means I have to take a shot to calm my nerves and then take a guess at which permutation of language features they decided to use today. A simple language is easier to read. This doesn't mean it's going to be easy for anyone who isn't a Go developer. There's no claims of that. But given a week to understand syntax and getting used to reading files, I don't think there's many places where you'd get stumped. >Go is an open source programming language that makes it easy to build simple, reliable, and efficient software. This still holds true for me. A simple language builds simple software. No noob Go dev is going to have a good time, but that's true in almost every language. Once you understand how everything works, how interfaces work, how channels work, you can simplify down most problems and build them with ease. Needing to write a few extra lines of code doesn't mean you can't write simple, reliable and efficient software. Neither of those quotes say Go is an all round easy language. It's not like you can throw it at a baby and get back Kubernetes. It's not easy to do custom containers, it's not easy to do manipulate lists, it's not easy to do a bunch of things you'd do in one line in something like C#. But I think these are small hurdles for the mental burden you're relieved of when you see that the rest of the language is equally as simple and benefits from it.
- domano 6y agoIn the go trainings i have given i noticed that syntax really was never the issue, but some concepts were awfully hard for some participants to understand. Also pointers are a thing people are afraid of for some reason. On the other hand i notice that most go code i have written does not need any maintenance at all, which is neat.
- divan 6y agoYou can't reply to someone's comment on internet about "...could pick up Go in 5-10 minutes..." that seriously. But couple of points about simplicity author missed out: - deleting from slice is expensive so should be explicit. True that lack of user generics prevents people to write own generic function for that, but that's not the only thing that generics will inevitably bring – are we still talking about complexity? - Go is still the easiest language to pick up and understand due to smaller basis in the feature vector space. That's what Go authors mean by orthogonality of features. The search for the solution is way more straightforward in Go space – and that's what we call a cognitive load.
- marvinblum 6y agoAgreed wholeheartedly. I professionally progammed in Java, PHP, and Go, alongside a few other languages for open-source/pet programms (Python, C, C++, ...) and finding a solution to a problem in Go is straightforward. When I had to write Java, I always had to decide which language feature I'd like to use first before getting down to the problem.
- marcus_holmes 6y ago> "I’ve seen many people coming from Python or C♯ try to shoehorn concepts or patterns from those languages in Go. Common ones include using struct embedding as inheritance, panics as exceptions, “pseudo-dynamic programming” with interface{}, and so forth. It rarely ends well, if ever." I've seen this so much. I did it too. You can almost watch people go through this process in places like r/golang. We all start off coming from a different language and being used to that, and while Go takes about an hour to learn all the syntax, it's only then that the learning starts. We all then try to write code the way we've always written it, only to find that Go doesn't work like that. Then we bump into the "this standard lib logging library is so shit, let's write a better one" (for the more ambitious, this is a whole framework). Then we learn more, and begin to realise why the logging lib is like that, and why there's no need for some kind of middleware construct, and so on. I'm not sure where this journey ends, because I haven't finished it yet - I suspect my understanding of chans and goroutines is incomplete because I still think they're "a bit clunky". Simple is hard. But good.
- majewsky 6y agoMy favorite way to summarize this is "some people can use any language to write Java" (or C or Python or Haskell etc.).
- zxcvbn4038 6y agoThinking outside the box, maybe people who don’t like Go ought to try a different language. Give Perl or Ruby a whirl. No memory management, no types, no concurrency, nothing to think about, just write code. Learn bash and never worry about arrays again. I knew a woman who went straight from 6502 assembly to bash. All her bash programs had two variables, $x and $y, and she reused them throughout. What other language gives you that freedom?
- zimbatm 6y agoIt depends what "easy" means. Go is a language that has very few surprises. As a beginner, it takes a while to figure out good goroutine design patterns. And you get bit by append to slice copies a few times. And it takes a bit of time to figure out how to structure code efficiently, and get over the fact that the code is not completely DRY. I'm sure I forgot a few gotchas, but this list is still a miles shorter than all the popular languages out there.
- val_deleplace 6y agoI agree with the 2 example tasks, which are not "simple" to write. The remove-by-value snippet is 8 lines, and it can be wrong in a subtle way: if list contains pointers, then we have a memory leak beyond the slice final length (pointer values still exists within capacity, and objects are not garbage collected). I wrote several possible implementations here, none of which is as concise and as obviously correct as an hypothetical "list.remove(v)": https://programming-idioms.org/idiom/136/remove-all-occurrences-of-a-value-from-a-list/1732/go https://programming-idioms.org/idiom/136/remove-all-occurren...
- labrador 6y agoEasy to learn doesn't necessarily mean easy to use, which I gather is where the "go is easy" meme got started. Morse code is easy to learn but hard to use.
- TurboHaskal 6y agoThe blog post misses the point. Of course writing idiomatic, gotcha-free, production ready code is never easy. But Go itself is comparatively easy. By far the fastest I have ever onboarded new engineers with, even more so than Python (which is terrible but somehow has a good reputation at being easy and friendly).
- aalhour 6y agoWhat is horrible about Python wrt onboarding new engineers? In my personal experience, I had an easier time getting onboarded on Python than Golang.
- TurboHaskal 6y agoEverything that happens in between development and deployment.
- 02020202 6y agoGo's simplicity forces you to write exact code and not use "magic" methods. It makes the code very readable and easy to understand right off the bet even if you have never worked with the project. Go IS easy, it's just on occasion a bit verbose due to the lack of generics or "magic" methods. That does not mean it is hard.
- captainbland 6y agoI'd say that Go in its current form is easy but tedious. Concurrency has some ways to shoot yourself in the foot but that's pretty much par for the course. The good news is it's going to become a lot less tedious if a little bit less easy with the introduction of generics.
- cletus 6y agoI'm a little surprised deleting an element from a list is this hard but that seems to be a case. That seems like an API oversight. You shouldn't be writing your own code for what is a fundamental operation. As for leaking Goroutines, yep that's a real thing. I had colleagues working on a Go project where exactly this was exhausting memory and causing the process to be killed. It can happen really easily. I view this as a fairly fundamental problem with GC languages. GC solves some problems of course but in doing so it creates other problems. For request-servicing type problems like servicing HTTP requests, I actually think the PHP/Hack model is pretty much ideal: stateless core (so low initialization costs unlike, say, Python), cooperative multitasking (ie no threads per se) and just throwing everything away after you're done. But I digress... What Go does have going for it is syntax. It's minimal, opinionated without being too opinionated (IMHO) and familiar to anyone who has ever used a C-style language. I tend to view Go as a better Python.
- jlouis 6y agoDeleting an element from a slice is a O(n) operation. It better be explicit in the program so the programmer knows just how expensive it is. Either you know what you are doing, and then writing it down is trivial, or you don't know what you are doing, and you are creating an efficiency problem for the future. Other data structures have a delete operation because it is efficient on those. And fully agree on the GC part. GC doesn't remove the work of resource management. It simplifies it vastly. This can some times lull people into thinking they can ignore resources altogether.
- cletus 6y agoYeah, I'm on board with the idea that expensive or not-recommended operations should be more verbose to discourage them. But you'll find other expensive operations (eg prepending an element to a slice) are much less verbose. At a certain point (of verbosity), you're just adding the potential for bugs.
- damagednoob 6y ago> Deleting an element from a slice is a O(n) operation. It better be explicit in the program so the programmer knows just how expensive it is. The chances of deleting an element in an array being a bottle-neck are really low. I'd rather save my brain cycles for thinking about disk/network access and wait for profiling to show me the problem.
- mybrid 6y agoSimple and easy are two words with no meaning. Why? Because simple and easy attest to common brain paths that do not exist. In computer science the divide between functional programming ease and simplicity as with the likes of Lisp and procedural languages as with like Python stand in stark contrast. Functional programmers believe everyone thinks like they do even though the vast majority of software is procedural and whose population do not find being lost in sets of parenthesis easy or simple. Easy and simple are meaningless because there is no uniform, blank slate learning path in the human brain. In fact, if one had to model every person having a unique learning path versus today's notion that what's easy from me is easy for thee then the unique model would surely realize far more efficacy in practice.
- eternalban 6y agoStatesments about ease of programming Go are relative. Go is easy once you internalize its semantics. And this is the kicker of Go, it remains simple even after you have achieved a level of mastery of the language. This is not the case even for a language like Java. Certainly, C++ gurus will have your eyes bleed reading their code. But this is not the case for Go, for the simple fact that Pike et al have engineered so that you can not do astronautics with Go, without enduring severe pain. So no one does it. Short of Go assembler code, any Go code out there is accessible to an exceptionally wide range of Go programmers. There is something to be said for that.
- netmonk 6y agoOP complains that GO official tutorial is all about syntax. So what are the ressources to learn GO specific mindset ? More generally, that was my concern back in the day with "The C programming language" which was only about how to write C code but not how to think in C. Which is quite different ! What are the best ressource online about how to think in a language (RUST/GO/C/C++/JAVA/JS/PYTHON/HASKELL/CAML...) ? Not only limited on about to syntaxically write a correct program !
- marvinblum 6y agoTutorials on source code structure and open-source projects.
- iandanforth 6y agoBarriers to entry are invisible. They are invisible to people on the inside and most frequently invisible to people who have a hand in creating those barriers. I once had a conversation with a founder about their signup flow. This founder had aspirations to be a global player. They said that step 2 of their flow included entering a credit card number. I had to stop them. "What about people who don't use credit cards?" They were nonplussed. "You know, China, much of Africa ..." they had never actually thought about whether people had credit cards because every single person they interacted with had one. Back to languages. If you've never taught an introduction to computer programming for a general audience you are blind to what does and does not matter about a language. You look at things like `foo.bar()` and think "Yeah that's a simple method invocation" and have no idea how many people you just lost. Never underestimate how much ease of use matters. We, as a community, have selected for decades against people who care about language ergonomics because they get hit in the face with a wall of punctuation filled text and turn away. We fight over where braces belong while not realizing how many hundreds of thousands of people we've excluded. Ease of use is the most important part of a language. It's just that the barriers to entry are invisible and so the people who happen to be well suited to vim vs emacs debates get to talk while the vast majority of potential programmers are left on the outside. We create barriers to entry accidentally because we design for people like us. To us the barriers are invisible.
- onlydeadheroes 6y agoI agree completely and I would add that the less mental effort you are spending on your language, the more you are using on your problem. This can have big effects on code and design quality, and allow you to grasp harder problems.
- solosoyokaze 6y agoA programming language is a tool. I don’t think it should really be optimized or designed around how easy it is to teach someone who is at step zero, basic programming concepts. I do think Go is a decent language to teach up and coming professional devs precisely because it doesn’t hide the real complexity of what’s going on, but I’d probably opt for something a bit higher level as the absolute intro to programming.
- d0100 6y ago> But I also don’t think that Go is a language that you “could pick up in ~5-10 minutes” I disagree. I use Go for our API backend because I can onboard junior developers and have them producing very fast. Because they are familiar with loops and C-syntax, this is very much a guaranteed "pick up in ~5-10 minutes" The explicitness of Go makes it easy for them to get to work, and easier for me to understand what they are doing when it comes to code review They won't ever have to use interface{}, nor concurrency, and slice manipulation won't take much time to lookup any "cheat sheet", or copy from another file
- klelatti 6y agoI hope "~5-10 minutes" is shorthand for a somewhat longer time periods. Even so have you considered whether this approach has some downsides and risks?
- d0100 6y agoSince we just work with mostly simple CRUD, there isn't many downsides. Also we use SQL queries for most of our logic, so SQL knowledge is the real barrier I usually ask them to read gobyexample.com, but they can start working on projects on the first day. CRUD project with Go makes it easy to add new endpoints and simple features, so we can focus on hiring frontend devs and smoothly turning them into "fullstack CRUD devs" I am sure this can be achieved with other languages, but for our use case (software-house) Go just fits really well because it provides a low cognitive overhead for juniors and even interns to make sense of the project and contribute It fits pretty nicely in an "assembly line" style development, but maybe the downside is that it is boring and makes devs want to leave because they feel like they're always hitting the mark and "mastered" development and want to climb to the next level. It seems reasonable for them, but the turnover is tiresome (around 6 months) for me
- klelatti 6y agoThanks - interesting perspective. I do think that we (or me!) hold ourselves to too high a standard in terms of mastering all aspects of a language, especially given some languages have got too big. It's refreshing to hear an approach that focuses on knowing just enough to get the job done!
- omginternets 6y agoThis article is built on a false premise: that people reach for Go because it is easy. Despite it's flaws (and it definitely has flaws), Go has replaced Python as my go-to language, not because it is easy but because it is small.
- dm03514 6y agoI love go, but I think it is a straight up dangerous language. I believe this because: - The tiny standard library and low learning curve make it quite easy to get started. - Concurrency is a first class citizen, through goroutines and channels - The performance, combined with the low barrier to entry, combined with its popularity make it very desirable for companies In my experiences this means a lot of companies without deep concurrent programming experience begin to adopt it. In my experiences this means concurrent programming errors....literally EVERYWHERE. I've seen (and created these of course) in every company I've been at and in huge open source go projects. I wish go would address this through first class tooling or type supported in the language like rust. I have a hueristic based approach that I've had success with when writing and reviewing code, but writing a static analysis tool for it is a bit out of my experience: https://medium.com/dm03514-tech-blog/golang-candidates-and-contexts-a-heuristic-approach-to-race-condition-detection-e2b230e70d08 https://medium.com/dm03514-tech-blog/golang-candidates-and-c...
- candiddevmike 6y agoCan you expand on the types of errors you're seeing? Go has a fairly powerful race detector you can run as part of your test suite that seems to catch everything I've thrown at it.
- dm03514 6y agoMe too! I generally think that the race detector is the best approach right now. At a prior job we had a lot of code that wasn't structured in a way that made it easy to exercise using the race detector. This was combined with misunderstanding about what the race detector did and didn't do. For example there was one team that ran `-race` on non-concurrent code, and expected it to verify race conditions.
- adsharma 6y agoThe idea behind https://github.com/adsharma/py2many https://github.com/adsharma/py2many is that you can still write: del a[i] and have the go code auto generated. py2many doesn't do that yet, but you can teach it to.
- erik_seaberg 6y agoThank you, I’ve been looking for something more actively used than https://github.com/google/grumpy https://github.com/google/grumpy.
- opportune 6y agoGo is not designed to be a scripting language. It is designed to have users think about edge cases and error handling so they are sure they are doing what they actually want to. Both the slice and goroutine patterns the author uses are pretty much standard patterns in Go, like making a factory function in a more OO language. To echo others, when Go makes something cumbersome (like an O(n) operation) it’s usually to hint to users that they’re doing something inefficient. But, agreed you can’t pick up Go in minutes. It’s best approached coming from a background of writing service binaries in C/C++. If you aren’t familiar with strong type systems and concurrency you’re going to have problems.
- fishywang 6y agoThere's so much wrong with the second example (it works, yes, but for all the wrong reasons) I don't even know where to start. Using the buffer size of a channel to control number of concurrent jobs is just the wrong approach. It's so much easier and cleaner to just use the number of goroutines for that: const workers = 3 const jobs = 20 jobsChan := make(chan int) var wg sync.WaitGroup for i := 0; i < workers; i++ { wg.Add(1) go func() { defer wg.Done() for work := range jobsChan { time.Sleep(time.Second) fmt.Println(work) } }() } for i := 1; i <= jobs; i++ { jobsChan <- i } close(jobsChan) wg.Wait() fmt.Println("done") One thing about channels in go is that the only time you want to use a buffered channel is the time that you know exactly how many writes (n) you'll have to the channel, while n is finite and reasonably small, so you create a channel with buffer size n to unblock all the writes. An example to that is that if you want to strictly enforce a timeout to a blocking call: const timeout = time.Millisecond*10 ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() resultChan := make(chan resultType, 1) go func() { result, err := myBlockCall(ctx) resultChan <- resultType{result, err} }() select { case <- ctx.Done(): return nil, ctx.Err() case r := <- resultChan: return r.result, r.err } If you are using a buffered channel in other cases, you are likely doing it wrong.
- aimatt 6y agoSome things are done on purpose so that you consciously know how expensive of an operation you are doing. In languages like Python, it's easy to abuse convenient operations that do a ton of computation. Then you have to spent time with valgrind or something similar and figure out what the heck is causing the code to be so slow.
- jaks_11_21_1982 6y agoTo be proficient in any language / framework you need to understand its mechanics. It doesn't matter what language you use. Or how easy it seems. I've seen many junior devs shooting in their feet with Java (Spring) or Node. And certainly did it myself often enough. After initial skepticism Go as become my personal go-to tool for backend, cli tools and throw away scripting stuff. At my workplace Go has replaced Spring and Node for standard business backend stuff as the standard stack. This is *not* because Go is such a fabulous and easy language, but because of its overall characteristics: - pretty impressive runtime performance and more importantly memory efficiency - large and very useful standard lib - useful tooling - stable and mature - encourages a package oriented design that enables large scale, however that can be achieved with many other languages as well. In other words: Building your app with packages as if they were microservices.
- Ambix 6y agoGo definitely not as simple and easy as many of newcomers think of :) The slices itself has many gotchas: https://medium.com/@gotzmann/so-you-think-you-know-go-c5164b0d0511 https://medium.com/@gotzmann/so-you-think-you-know-go-c5164b...
- jy3 6y ago> There are a number of patterns to limit the number of goroutines, and none of them are exactly easy. A simple example might be something like: This is probably what the author was looking for https://pkg.go.dev/golang.org/x/sync/semaphore https://pkg.go.dev/golang.org/x/sync/semaphore
- jeffkayser 6y agoWhy gripe about how difficult it is to do concurrency in Go? It is difficult to do concurrency correctly in ANY mainstream language. Go offers more support for concurrency than most: goroutines, channels, non-blocking I/O, great networking and HTTP support, ... There is a book specifically about this ("Concurrency in Go" by Katherine Cox-Buday) that carefully explains how to do concurrency correctly in Go. Go has become the language of cloud infrastructure: https://hackernoon.com/go-has-indeed-become-the-language-of-cloud-infrastructure-rob-pike-q51a3wle https://hackernoon.com/go-has-indeed-become-the-language-of-... And there are lots of developers who want to use it: https://zoolatech.com/blog/why-use-golang-for-your-project-a-most-wanted-programming-language-in-2020/ https://zoolatech.com/blog/why-use-golang-for-your-project-a... Are there things we would want added to the language? Sure. Generics. Check out the progress: https://thenewstack.io/this-week-in-programming-go-approves-generics-long-at-last/ https://thenewstack.io/this-week-in-programming-go-approves-... If there are other things you want added, it's open source, and you can join the team working on it. Don't lose sight of the fact that Go has done alot of things right, and is GREAT the way it is right now. The uptake in the developer community proves it's worth.