I don't share some of the opinions I see in the comments here.
I've recently started programming in Go and I am having a blast. Plus, I am making my systems faster and simpler with Go. I love concurrency in Go. I love the concept of Goroutines, the simple and intuitive use of Select. Channels still present a few mysteries here and there... But I'll get it at some point.
But the n#1 thing for me in Go is: It's written in Go. It's refreshing to drill into the language details, I feel like I have learned so much from seeing the Go source code (and having it readily available with a Ctrl+click in VS Code).
Maybe it's because I don't have the "depth" of some of the HN users, but Go feels great to me.
I agree with you, I didn't know how to build a webapp, two years ago, I learned the basics and implemented a fully working webapp in Go along with the REST client, all without having to buy a single book, the docs are amazing, the community is amazing and the language made me build things fast, I love GOPATH, I love gofmt. Apart from the tooling, I felt as if I have been writing Go since a long time, even though I was just a newbie, my app: http://github.com/thewhitetulip/Tasks/
Thank you for your kind words! I am happy that you like it, I am writing a series of guides on vi, python, git and probably bash along with their YouTube series, you can find them here http://github.com/thewhitetulip/multiversity
Maybe it's because I don't have the "depth"
of some of the HN users, but Go feels great to me.
I doubt I have any more depth than you as a programmer, but I've gone one step farther than you down the language safety progression, so maybe my thoughts from here will be interesting.
When I moved from Python to Go not only did my code become more safe, I actually became a better programmer. There are a lot of silly things that you can do in Python that you can justify saying "just this once!" or "it's only temporary!" that are much harder to do with Go. I started writing a lot less complicated functions that did different things with different types, and moved to writing simpler, single purpose functions whenever possible. This was great and I learned a lot.
Then I moved from Go to Haskell, and the same thing happened again.
Haskell makes you specify whether a type can be null or not. It has referential transparency, so you can't mutate variables as a side effect of a function. It has sum types, eg:
data User = Unauthenticated | Normal UserId | Admin UserId
.. that make it really easy to enforce invariants and are also super convenient to use because of pattern matching. I write a lot less "stringly typed" code now than I did when using Python or Go.
Now there are downsides -- Go has a great standard library, and it's tooling is fantastic (even down to little things like gofmt). I'm not saying you'd have a better experience with Haskell, just that there are real reasons why someone wouldn't want to go back after trying a more featureful language than Go.
But Go really does encourage good practices. I came to Go after programming in C, C++, Java and a bunch of dynamically typed languages. After a couple of years with Go I returned to C (and a bit to Java). And I'm writing better code in those languages now.
Now, part of it is natural progress probably. But especially when I'm writing C, I can tell that I'm writing it much better than before because I'm adopting back some idioms that Go encouraged me to adopt in the first place.
Also, because Go's standard library is so well written, you can learn from the best very easily, and understand what's going on. It's certainly not the case with other languages I write in.
I suspect every time you move to a different language family you learn new things. I did C/C++ and Java then worked with an old Pascal codebase of all things that IMO taught me more than most other languages. Even XSLT taught me quite a bit.
I can't say that Java has improved me in any language, but Go and Python have improved my Java. But any time you learn new idioms in a new language, your understanding of programming gets better I suppose.
Is there a good resource where those good transferable go idioms are written? I dont think I will have time to learn go anytime soon, but would definitely spent time with an article or something like that.
Not that I know of, but Go is super easy to learn. You will get a grip of the basics and be productive over a few hours or weekend at most, and one or two hobby projects later you'll learn to appreciate the stuff I'm talking about.
BTW I've only felt I really knew the language and its inner workings and idioms deeply - after much longer, maybe a year and 2-3 big projects. But you get very productive very fast.
Not only that, but rarely am I supporting a library that I'm the sole developer on. Go takes away so much "individuality" of code. On most teams I've been on with Python and Java I can open up a file and immediate tell who wrote the library based on various style and other such. It's a lot harder with Go and that's a very good thing.
Yeah, at times the obsession of gophers with "idiomatic code" is annoying. But when you read someone else's code and it's idiomatic, you almost immediately have an intuitive sense how it works and can understand and modify it easily. Compared to Java OO code where you have to start chasing inheritance layers to find out where the piece of logic you're actually interested in resides...
Well, "idiomatic code" can often mean "for what you're trying to do, there is a way that works with the language better than any other way; do that". That is, it often means "working with the tool rather than fighting it". So, yeah, do it the idiomatic way unless another way is clearly better. (Idiomatic ought to win if evaluating "better" gives you a tie, because idiomatic will be more readable.)
I never really stopped to think about it until I read your comment, but I just realized the same applies to old Go code. As some of mine is approaching probably close to 2-3 years (and few things I haven't touched or looked at since!), and while it certainly could be rewritten to be better, it's interesting that Go's partial enforcement of idiomatic authorship appears to reduce the number of WTFs generated as a consequence of atrophy over time, to say nothing about how much less time is spent understanding the code.
Perhaps it's psychosomatic, but it sure seems easier to pick up something written in Go--long since forgotten--than it is in other languages. Then again, maybe it's also that Go taught me to substitute cleverness with terseness. The advantage here is that I've never been especially clever.
I'm with you. IMHO, Go's simplicity is its biggest virtue. It has fostered a community that values consistency and clarity over syntactic sugar. And, as a result, I find each new codebase extremely accessible.
Normally it's the other way around, Go gets compared to other "Systems Programming" languages because somehow services got lumped in with that name over the last few years.
To me they're very discrete things, if you can't manually manage memory(raw pointers and the like) then it's not a System Programming language.
Go gets compared to "systems programming" languages because its designers specifically intended it to be used as such [1][2], albeit the definition of 'systems' they are using is deliberately evolved from the original shade of meaning as suggested by low-level languages that are sometimes deemed to be for 'systems programming' to illustrate that the nature of environments has changed, and a new approach is advantageous.
It gets compared with them because that is what it is particularly good for. Arguably, it is much less suited to Type 1 representational systems (http://aryehoffman.com/entry/project-types), for the same reasons as for the C language. Like C, it is particularly suited to Type 2a projects - those in computing and its infrastructure.
Rust, too, had an optional GC (where the choice is per-data, not global) for a long time and still intended to be a systems language (And was pretty successful at being systemsy IMO). I think there was a time when &-pointers didn't exist and all sharing was done through the GC too. At one point there was a realization that the new borrowing system could be used to write GC-less programs pretty easily, and that was a turning point after which the GC started being phased out in community usage and eventually removed from the language.
I never said anything about having a GC, just that if you can't poke directly at memory when you need to then you're going to have a heck of a time working on the Systems Programming space.
Also remember Go was inspired a lot by Oberon-2. The Oberon languages were used for writing operating systems despite a GC. They just used assembly or UNSAFE constructs for stuff the type-safe or GC parts couldn't handle.
I think you have this backwards. 'Systems programming' has never meant 'operating systems'. To believe that Go is misdescribed as a 'systems programming' language you have to believe Rob Pike doesn't know what 'systems programming' means.
Given Pike's extensive experience inside a world of his own making (Plan 9 and Go), it's entirely reasonable to attribute the misconception that Go is a system language to Pike's idiosyncratic use of the phrase.
If I understand things correctly, Go came about as fallout related to the non-scalability of Python and the massive technical debt associated with Python within Google. The projects to automagically port Python code to Go code are a clear indicator that Go was at least in part imagined as a replacement for Python.
I personally wouldn't describe Python as a systems language, but some might.
There's nothing idiosyncratic about it. "Systems Programming" has meant a lot more than just "operating systems" for at least as long as I've been doing this stuff, which dates back into the 90's. Maybe in some earlier age it was the case that "Systems Programming" was limited to "operating systems" but if so, it was quite some time ago. Language evolves...
Yeah, one of the cool things about go is it's ability to get reasonable compile times without byzantine management of include files, as in c++. I still don't know of any major c++ code base being targeted by go, whereas python is certainly in the crosshairs.
The primary distinguishing characteristic of systems programming when compared to application programming is that application programming aims to produce software which provides services to the user directly (e.g. word processor), whereas systems programming aims to produce software and software platforms which provide services to other software, are performance constrained, or bothhttps://en.wikipedia.org/wiki/System_programming
By that definition it seems pretty clear that systems programming covers a lot more than just operating systems. But calling a language a systems programming language if it is unsuitable for writing operating systems seems a bit unusual. At least it would have been unusual at the time these terms were originally coined.
Why would I? They support what I said directly - 'system programming' is not limited to operating systems. Here's a bit from one of the Wikipedia entries you mention.
"System software is computer software designed to operate and control the computer hardware, and to provide a platform for running application software. System software is computer software designed to operate and control the computer hardware, and to provide a platform for running application software. System software includes software categories such as operating systems, utility software, device drivers, compilers, and linkers."
"System software includes software categories such as operating systems, utility software, device drivers, compilers, and linkers"
Most of those things can be summed up as "operating systems" (operating system, device drivers, and utility software, e.g. basic backend services) plus some essential supporting stuff (compiler and linker).
So, yeah, it's pretty much constrained to "operating systems" and the few essential items. It's not about network servers the kind Go is used for.
In my experience, pvg is correct. It's been ages since "systems programming" was limited to just "operating systems" from what I can see. I don't know anybody who wouldn't refer to writing middleware or network servers as "systems programming".
So it's not constrained to operating systems but it's pretty much constrained to operating systems. You can see how I'm less than convinced.
It's just not a precisely defined technical term and in a computer language really has more to do with the intent and purpose of the designers and implementors and the operational context than things like 'has manual memory management' or 'must be used for writing an actual operating system'. By your strange definition, writing an NFS server would not be 'systems programming' because for some reason networking is excluded. I don't find this seemingly arbitrary distinction convincing either.
>So it's not constrained to operating systems but it's pretty much constrained to operating systems. You can see how I'm less than convinced.
It's just that operating systems is not just the kernel. The POSIX userland of tools (ls, cat, ps, etc) are also systems programming, and essential part of an OS. And of course device drivers (which they even get linked or loaded directly to the kernel).
Postgres, Varnish, redis, or Apache on the other hand, or some ad-hoc enterprise backend service, is not "systems programming".
>* By your strange definition, writing an NFS server would not be 'systems programming' because for some reason networking is excluded.*
Never said that "networking is exclude". The TCP/IP stack is very much systems programming, as an example. And NFS would be too, as it's still a kind of filesystem (and thus working with the kernel and OS at a low level), and an essential part of a POSIX system.
Some load balancer for MySQL, on the other hand (one of Go's touted examples), not that much.
The definition of 'systems programming' is certainly wooly (and predates all of your examples) but I don't think it's an iterative stochastic hairsplitting fractal, like you're proposing. You've basically argued your way to a corner in which varnish and apache are not 'systems programming'. That's not a sensible use of the term.
Systems are relationships between input from the environment, algorithms/functions to process it, and output to the environment. Basically programs at a high-level representation. Systems analysis, design, and implementation started with basic control systems far as I can tell. At some point, there was a distinction between "systems" and "application" programming made by whoever. Original meaning of the term covered all programming where you then picked tools (eg languages) best suited for particular task.
Go's predecessors... Oberon-2, C, and Limbo... were two languages for OS's plus a distributed, systems language. Go's core is the first two with last being mainly for concurrency IIRC. That with ability to do unsafe stuff makes me think of Go as a systems language used mainly for regular applications.
And further, in my view, if manual memory management is extraordinarily difficult a language is not necessarily a good candidate for systems programming.
You can relatively easily get to manual memory management using Go's runtime, i.e. access those runtime·sysAlloc(), runtime·sysFree() functions directly, the way Go accesses syscalls in the external sys package [1]. It's like ten lines of code, nothing extraordinarily difficult.
The difficulty of manually managing memory isn't necessarily to do with how many lines of code it takes to allocate or deallocate. The difficulty is in managing the scope of the rest of the program that is now susceptible to memory errors, which extends far beyond those initial ten lines of code if encapsulation is done inexpertly.
Yeah i love go and i am a C++ and Fortran dev by day. For me go just gets out of the way, and its just so easy to build actual things quickly. AND you get a static binary out of it which gets rid of the deployment issues with python.
Go is a really good git-r-done tool. There's nothing wrong with that despite what some would have you believe.
Our internal dashboard is Elm but the back end is mostly Go. Both have their pros and cons but both work. That's more than I can say for many other dev tools.
> Maybe it's because I don't have the "depth" of some of the HN users, but Go feels great to me.
I've been writing Go full-time as my primary language for nearly five years. Before that, my languages of choice were Lisp[0] and Python, with R as a very distant third choice[1]. I have always been a polyglot and enjoyed experimenting with any new language I could try out - you'd be hard pressed to name a non-esoteric language that I haven't written more than a "Hello, World" in at some point.
I still write other languages and appreciate them for what they are, but Go is what I reach for when I need to crank something out. The language gets out of my way and doesn't distract me - and as an added bonus, I can be reasonably confident that I can quickly refactor the code 6 months later and still have it run[2]. Go is not a scripting languages, but I sometimes even write small applications in Go that I would have previously written as shell scripts, just because it's easier and less thorny than remembering to avoid all of the pitfalls of shell scripting.
You might say that this is because I've been writing the language for so long - and yes, I'm definitely more comfortable with it today than I was in 2012. But everything I just said was still true even when I was only a few weeks into learning the language. It was like putting on glasses for the first time in my life - yes, I could "see" before, but somehow everything was just a little bit crisper, and I felt incomprehensibly more powerful and capable when writing Go compared to Lisp, Python, Scala, Java, Perl... despite having far more years of experience in those other languages.
If some people don't want to use Go, that's fine with me. But I strongly reject the criticisms that Go is meant for "mediocre" programmers, for programmers without experience in functional languages, or somehow an inferior language because it lacks feature X or Y from language Z.
[0] Common Lisp (via SBCL) or Racket, depending on the project and collaborators
[1] It's a language with a lot of warts, but even Python couldn't touch R for completeness in statistical libraries.
[2] Seriously, I have never found a language that made refactoring as easy - or, dare I say fun? - as Go.
>If some people don't want to use Go, that's fine with me. But I strongly reject the criticisms that Go is meant for "mediocre" programmers, for programmers without experience in functional languages, or somehow an inferior language because it lacks feature X or Y from language Z.
I think such complaints are the predictable backlash that's correlated with the final stage of its hype-cycle. Tech hipsters always need a hot new thing to tout so that they can pretend to know what they're talking about.
Now that we have a new iteration of hyped languages in Swift, TypeScript, and Elixir, Scala, Go, and node.js are on the hipsterdom downtrend (which often also means they're on the mature user uptrend). That prior generation of languages are now at least semi-widely known, so they no longer serve the purposes of the talentless hipsters, who base their self-worth on the esoteric nature of their preferences and need something that most people don't yet know much about to hide their ineptitude.
I think Python is a great example of a community that built a real niche for itself and legitimately earned the respect of mature, senior engineers by repeatedly proving and improving its utility and stability for many years. Giving Go the opportunity to develop this same type of sustainable, consistent, healthily growing ecosystem without a flood of 0.1x programmers and other hipsters is really the best thing for it. I'm optimistic for Go in the long term.
At the beginning of the Java and the XML hype cycles few people called that out the new toys weren't as shiny as they looked on the box. It took 10, maybe 15, years for others to catch up.
Look behind hype cycles and often you'll find $company marketing department.
I'm responding to criticisms in this and other HN threads about Go, so yes, I'm talking about a criticism.
> it's literally how the Go language creators themselves describe it. See the Rob Pike quote
Unless you think Rob Pike is saying that Google is hiring mediocre programmers (hint: he's not), that statement is intended as a criticism of academics ("researchers"). He's saying that the same things that excite researchers about programming languages don't lend themselves to good software engineering in industry. (And he's right).
But regardless of what the creators of the language may have intended, I'm saying that the criticism regarding experience with functional languages is flat-out wrong. I've written more code in various functional languages than the overwhelming majority of people who read this site - both on and off the clock - and I'm testifying that yes, even for someone who has deep experience with functional language of both the Lisp and the SML families, Go still has a lot to offer that very few others do.
> Unless you think Rob Pike is saying that Google is hiring mediocre programmers (hint: he's not),
Actually that's exactly what he's saying - although "inexperienced" is probably a better word than mediocre.
Golang is the modern blub language. It's really great for large companies and big code bases used by many people who want to get quickly up to speed. A decent, even new, programmer can get up to speed and be very productive in Golang in a matter of weeks. I can go and read the Kubernetes code base, which is huge, and know exactly what's going on pretty quickly, despite the complexities in that codebase like code generation and massive concurrency.
A language like Rust on the other hand would take months before someone can be seriously productive in it. That has a very real cost. It's sacrificing short term productivity for the long term benefits.
I think for a big company like Google, with so much staff, many inexperienced, and relatively high turnover (lots of people leaving and going constantly), a language like Golang is perfect.
At a small hedge fund, where you have maybe a dozen or two lifers, investing in a more strategic language like Haskell, Rust, OCaml, etc. starts to become viable.
Bah, a language being 'easy to get up to speed with' and 'a perfect fit for large teams working on huge code bases' should be a clue to stay the hell away from it.
Because if Golang maintains its current momentum, someday soon the developing world will start pumping out legions of mediocre Golang coders, just as they did with Java.
OK. I should have said, it's not inherently a criticism, it's just a fact. That others may choose to use it as a criticism--well, that's upto them.
Personally I don't think there's such a thing as a 'mediocre' programmer, I think there are programmers who have studied and trained in concepts, techniques and idioms and those who haven't.
It seems pretty clear from that quote that Google is hiring kids fresh out of college, and instead of training and educating them they're throwing them at an intentionally simplified language to get them to churn out code quickly.
Also I find it hard to believe that type-safety guarantees don't lead to good software engineering in industry, when the biggest industrial users of Python, PHP, JavaScript and Clojure--the dynamic language titans of the tech industry--have all recently developed and popularised type systems for them.
And in fact, I also don't see how you can derive a criticism of academia out of those quotes when they mention 'researchers' only in passing, as a point of comparison to talk about their coders' skill level. Too much mental gymnastics for me.
> I think there are programmers who have studied and trained in concepts, techniques and idioms and those who haven't
Which is really just talking in circles, because as I've now said in three consecutive comments, I have quite extensive experience with functional programming, and so I'm rejecting the argument that Go is simply for people who don't have that experience.
> And in fact, I also don't see how you can derive a criticism of academia out of those quotes when they mention 'researchers' only in passing, as a point of comparison to talk about their coders' skill level.
It's probably because, in five years of writing the language, I've had the opportunity to hear Pike (and others) talk about the topic. So when I'm responding, I'm drawing on that body of knowledge to inform what I'm saying, rather than limiting myself to a single quotation cited on a blog post written by someone who (by his own admission) is very new to the language.
> Unless you think Rob Pike is saying that Google is hiring mediocre programmers (hint: he's not), that statement is intended as a criticism of academics ("researchers"). He's saying that the same things that excite researchers about programming languages don't lend themselves to good software engineering in industry. (And he's right).
If that was the case, it was a very dubious thought. Before Go was launched, the languages used in Google were Java, Python and C++. None of them look academic, none of them seem to require another language that is specifically designed to "unexcite" newcomers. Neither is functional, really.
>I strongly reject the criticisms that Go is meant for "mediocre" programmers
I don't know how else to describe people who don't resent being second-class citizens under the library designers, who don't insist on being able to create their own abstractions and use them with the operators that slices or maps support. The language has extensible interfaces but doesn't use them for things like iteration and equality.
> I don't know how else to describe people who don't resent being second-class citizens under the library designers...
One suggestion: describe them as "people who have a different opinion than I do", rather than automatically concluding that anyone who doesn't feel the same way as you do about something must be "mediocre". There are popular languages that I can't stand writing, and languages that I think are badly designed, but I would never be tempted to say that those languages are "for mediocre programmers" just because they don't have the attributes that I look for.
As a polyglot, I can definitively say that every language in widespread use is "missing" something in its design that, at first glance, would be glaringly obvious to someone who's used to a different language. If anything, the sign of a good programmer (as opposed to a mediocre one) is the ability to conceptualize why a language might be successful despite (or even because of) this apparent "flaw".
>One suggestion: describe them as "people who have a different opinion than I do"
Some "different opinions" are just different opinions, other "different opinions" do indeed point to mediocre programmers.
I'm not saying that is the case with Go: just that what you wrote is orthogonal. One can have a different opinion that is NOT to be respected, but dismissed. Not everything is equally valid.
Especially when compared to working with something like Spring Boot every day it's fantastic. Getting rid of all the bloat is a bigger win than any of its unique features in my opinion.
I suppose most of my negative experiences with it are specifically in the context of using it to build microservices. The memory usage alone created a bit of a problem, I ended up using nearly all of my 16GB of RAM when I had to run many services simultaneously. And because the functionality of any given service was fairly minimal, there really wasn't a need for a framework like that.
The autoconfiguratuon was also a bit dangerous. Since any dependency could cause any other dependency to reconfigure itself, it made it difficult to determine why things would break at times. At one point one of our libraries that used RabbitMQ behaved differently in some other services because another dependency saw RabbitMQ on the class path and started trying to use queues that didn't exist. Someone spent a day and a half figuring that out because the error was being swallowed by something else so the application was just failing to start with some crypic error. And when autoconfiguration wasn't enough, you'd sometimes find yourself needing to write dozens of lines of Java to do something as simple as connecting to a second database.
In general I found we tended to have less predictable or obvious behavior in our Spring apps, and they tended to be more likely to fail at runtime than I would've liked.
I usually get rid of @EnableAutoConfiguration and then selectively import the auto-configuration classes I actually want with @ImportAutoConfiguration.
A Spring developer once mentioned, on a mailing list post i have long since lost, that the autoconfiguration stuff is pretty much demo-ware. It's good for getting a simple app up and running fast, but for anything serious, you should import the configurations manually, exactly as you say. Fortunately, that's an easy enough transition to make at any point in a project's lifetime.
For me, I imagine the dropwizard guys sat round asking each other what the best servlet container is, web MVC tool, ORM, DI framework, etc, etc. and they choose the very best they can think of for a dev to work with.
Then a couple of years later that company comes along where they ask the same questions and but there's a guy with Tourette's in the corner and Every. Single. Time. the answer to the question is SPRING!! SPRING!! SPRING'S THE RIGHT ANSWER!! SPRING!
From the moment you boot spring boot and discover how much longer it takes to boot it's a struggle not to question the motivations of a place where the answer's the same no matter the question.
I don't know. I feel like if I need something productive, I would go very high level like Python. In the VERY rare case Python is too slow, I would go really low level like rust.
I don't see the interest for something that not really low level, but not realy high level either like Go. If concurrency is the main issue and is the niche I'm targeting, I would go Erlang or Elixir.
For me Go is the goto language for usecases where Python and Java were used. Python is great for tooling, and Java was the primary language for the backend.
So now, whenever i think about tooling or backend, Go is the primary answer, because its good in both paradigms.
The other languages i use is C++, and Swift, each one with their own niches. C++ for complex machinery, that requires more control and integration with other libs, and Swift for general applications, specially the ones that are user focused.
In my case, i cant find a niche for Rust. And thats because C++ is already covering that ground for me. I can see why i would use Rust instead of C++, but in the majority of cases where i use C++, there are huge complementary source code already in C++, making the effort to code everything in Rust from scratch, a complete nonsense.
So for me the language in "limbo" right now is Rust. (and i dont think that people with big C++ codebases would rewrite in Rust, because there's little advantage, at least compared to modern C++)
For me C++ (or Rust) would be the languages to go for Browsers, VM's, Compilers, Game Engines, Glue Code for a OS(platform layer to prepare things for a app to run) etc..
The problem is, there's a lot of code in C++ already for all of this. V8, Dart, Java Vm's in C++, Webkit, Chrome, Firefox in C++, great game engines in C++.
Is not that i wouldnt use Rust.. on the contrary. But the problem is, for the usecase i think Rust would be very good, there are a lot of code in C++ already, that would require a effort of years to port in Rust.
For instance i work in Chrome C++ source a lot.. and the codebase is a beast.
Maybe if, in the future, things that are starting now in Rust, will be the the successful cases for this kind of machinery.
But given that, at least i, wouldnt use Rust to make a webserver backend (the same way i wouldnt use C++ for that), because i think its overkill. While i like Rust, i cant see a opportunity to use it, and the great impediment for that, is the C++ codebase legacy, and both languages basically competing for the same paradigm.
But theres a great thing in favor of Rust, because its the only modern real contender to C++. But i think it will be a slow and harsh competition (albeit a necessary one).
Cool, totally get this argument. I was mostly curious if you were thinking about something in Rust, but then found the libraries lacking, as we're trying to work on filling in gaps here.
Yes. And just to make it clear, when i say "in limbo" is actually a compliment, in a sense that i want to use it, but didnt found the right opportunity to do so.
I would be glad to be able to use Go, Swift and Rust, instead of Go, Swift and C++. Its just that i cant find a way to do so, and it has nothing to do with Rust the language, the ecosystem and the community. They are all awesome.
The target audience is people who don't know Elixir and Rust, have no time and not enough conceptual base to learn them in a reasonable time, and have to ship concurrent code, fast. Go is stupidly simple; this can also be an upside.
Python's concurrency story is much better in 3.5+ than in 2.x, but a lot of people use 2.x for various reasons.
Turns out also that, from an organizational perspective, it can take a lot to support n+1 programming languages. A codebase with 10 languages is more difficult to maintain than one with 2 or 3.
As a result I think there is large benefit to having a language like Go -- it satisfies many overlapping needs, and organizations can avoid adopting too many other languages that fulfill niche areas.
At Google there are only (5) core / officially supported languages: Python, Javascript, Java, C++, and Go.
Python is generally applied in a scripting context. Javascript in frontend context. Java / C++ where you'd expect. Go for writing servers, application infra, tools, scripts, etc.
Given some of the comments, I'll make the same comment I've made before: Stroustrup is right, there are languages that people complain about, and languages that no-one uses. Go is now firmly in the former camp.
I'm a C++ dev, and I really enjoy using Go. If you don't like what it does or how it does it, it's not for you. Either way, people are out there using it, making systems from it, and generally getting on with it.
> Stroustrup is right, there are languages that people complain about, and languages that no-one uses.
This quote has always struck me as an intellectually lazy cop out to avoid engaging with criticism. It's an indirect appeal to the fallacy of false equivalence: "If people actually used language $Foo, surely they would complain about it just as much, because all programming languages are basically the same."
> Either way, people are out there using it, making systems from it, and generally getting on with it.
See, this argument could be used to dismiss any criticism of just about anything.
To me that quote says that there's no such thing as a perfect language.
Different tools for different jobs. If you wander too far from the main domain of the language, you'll find quirks and it's maybe better to use something else.
Go's success is attributable to the fact that it is the first compiled language in a long time which is backed by a major company and has managed to deliver a simple and enriched experience compared to the old company backed compiled languages.
1. Fast compilation is a killer feature.
2. Ease of deployment, as a self contained executable (static linked), is a joy.
3. Channels are a revolutionary concept to every programmer who had only touched mainstay languages.
4. Type inference is a revolutionary concept to every programmer who had only touched mainstay languages.
5. Go's syntax is less verbose than all other earlier mainstay languages. Such as how public/private is handled through casing, and not having to type public or private.
6. Go's structural typing is a revolutionary concept to every programmer who had only touched mainstay languages.
7. Everything that's new in Go to a programmer who had only touched mainstay languages before it is not there in Go as an extra set of features, but the only thing for them to use. This greatly focuses them on learning those new features. Also, non of the features are too radical to throw them off completely.
8. All the tools for Go, are built by the team behind Go.
9. Go's battery included, and has a great selection of modern standard libs.
When compared to Java, Go lacks very little, and brings a lot to the table. Generics are probably the biggest omission, but that's probably going to make it in the language eventually.
The best summary I read recently is that go isn't a bad language, nor is it a particularly good one. What fascinates me is the way the Golang community have concretised that essential middle-of-the-roadness as the language's prime virtue. That, of course, has long been Java's prime virtue as well. (see Blub Paradox)
By putting "we're okay with being okay" as your Big Thing you're clearly pitching for that vast bulk of mid-quality developers that make up the huge middle chunk of corporate devs, the space where Java reigns supreme.
Nah. I like Go because the language itself is minimal yet powerful, and because the quality of engineering is extremely high. I am so tired of having to deal with bullshit because of poorly-thought-out and poorly-engineered tools; Go minimizes that.
An excellent example is the handling of this bug report(§):
I feel like any other language I've used would've just added a "monotonicTime" function and called it a day; the Go solution is impressive, elegant, and shows an exceedingly high level of care for the end-outcome results for the users of the language.
To me, that's what makes Go special.
(§After a rocky start; it took the core devs a bit to realize it was a real issue because within Google's special environment it isn't.)
I dunno... in some ways, the problem is that they didn't think it through to begin with, and chose something widely-known-to-be-ambiguous-and-problematic like "time.Now()", instead of choosing unambiguous names / structures from the start.
It's kinda the equivalent of making a new language (nowadays) and not defining what encoding your native strings use. Of course it's going to cause problems. Except the timer issue has been around much longer than the standardization on utf-8.
Fair point! And I certainly don't claim that the Go devs don't make mistakes. They started with the theory that the problem should solved as Google does, by arranging that clocks don't run backwards. When it become clear that wasn't reasonable, they moved towards a new solution in a way that I felt was impressive.
It's mostly-impressively backwards compatible, I'll definitely agree there. It's clever, and in many cases it'll do the right thing automatically. Since it seems that's their goal, they achieved it quite elegantly, and that's a tricky thing to do. (edit: and quite quickly! seriously, this is an example of a healthy community at its best)
But personally I don't agree with the decision - it adds surprises when you try to convert times to other types and then compare things. Or convert to something else and then back to a time instance. I've watched things like this become the source of bugs many, many times - this will only make that worse, since now a "time" is two values but you can really only access one of them (the one that's equivalent to wall-clock, which is causing the problems). And they're particularly painful bugs, because the cause lies in implicit conversions and behavior. That seems to run counter to the "minimal surprises" that Go seems to prioritize.
There's no denying it's at least flirting with "too clever" territory. What saves it for me is (1) the analysis of a large body of code that seemed to show only positive impact (2) that the behavior is well-documented and (3) anytime you're converting between types, you should always be thinking, "what is the range of these types? what information might get lost?", which with (2), should leave you alright.
But, I could easily see looking back in 2 years and realizing you were right.
"Should", definitely :) Easier said than done. But I'm happy to wait and see, it's not like this would make Go the only language with weird time handling. As it stands they're probably in a better place than most people are used to.
That code-corpus-analysis is pretty neat, I hadn't looked through in detail before. Thanks for pointing it out!
---
Sorta as an aside, it seems the proposal can lead to:
If both times have mono time, then Equal() compares that, and ignores wall time.
So t2.Equal(t1) is true.
You are right that "t1 == t2" (comparing the raw bytes of the time structures) is false, but that was already broken anyway (because time-zones break raw byte equality).
(Whether you think it's OK to have a language that doesn't overload == and makes you know that for complex structures you've got to call a method like Equal() probably correlates pretty highly with your opinion of Go.)
There will of course be other weird things, like:
print(t1) // "20 [20]"
print(t2) // "19 [20]"
But you could argue that's basically the least-surprising possible result in the face of the surprising fact time having gone backwards one second. :)
By the way, worth mentioning that while this is all implemented in HEAD in Go, it's not a done deal yet -- it'll have a 3-month window for people to try it out in the real world, and if it's found to be problematic, it'll get backed out before becoming part of the official release.
>If both times have mono time, then Equal() compares that, and ignores wall time.
Gotcha, I missed that somewhere. That's essentially fine - then the only real surprises are when you deserialize a Time (so it doesn't have a mono time), which should in principle have no interactions with this proposal.
And yeah, Equal vs ==, the meaning was clear enough that I didn't bother to be specific :) Thanks for the infos!
I am so tired of having to deal with bullshit because of poorly-thought-out and poorly-engineered tools
Seems to be some cognitive dissonance (in the modern erroneous sense of the word) going on. This was a hack necessary because the design of the library wasn't fully thought out. Imagining the world would one day become Google is not thinking things out.
It was something not in the library because it wasn't in their sphere of consideration. When that expanded, due to feedback from the outside world, they responded in an impressive way.
And that's just an example that was intended to illustrative.
You'll just have to take my word for it that my experience of the Go ecosystem, tools, and standard library has been more solid than the various other things I've used over the years (python, C# + unity, c++, fucking maven, boost...).
If I'm missing out on something even better, let me know. ;-)
> you're clearly pitching for that vast bulk of mid-quality developers that make up the huge middle chunk of corporate devs
That was actually something Google aimed for with Go, and I don't see what is shameful about it. It's a simple language on purpose. It is meant to be easily learned by any developer, and similarly Go code is meant to be easily read.
Also, what sets Go apart for me, in addition to this simplicity, is the tooling and documentation. I think people mistakenly yearn for languages that are exciting to use or offer interesting abstractions. This stuff is fun for the individual developer but costs an organization in the long run.
Go is bland on purpose. Notice how between versions most of the headline updates are internal improvements (GC, tooling, general performance)
When I think about Go in comparison to other languages, I think of car metaphors. Lots of people talk about cars that are good. Some people think a good car is fast, some people think a good car is low maintenance, some people think a good car is eye-catching. They are all right, those are all descriptors of good cars.
Go, however, is like a Toyota Corolla or a Honda Civic. It's dependable, but relatively plain. It's not necessarily a joy to drive but there's not much of a learning curve. It lets you go fast, but not so fast you'd hurt yourself. It's designed with safety in mind, so much so that it can feel a little over-bearing at times.
It's not a language that draws you in with one clear feature or philosophy. I've used it very successfully and I still find myself rolling my eyes at "go-isms." Lines of "ok, err = ...", rewriting extremely similar data structures, careful channel management, etc. In a list of dependencies, the go dependency will need the least maintenance time and tuning, but what you do need will often be drudgery.
Go is a useful language, but it's a language that has purposefully stripped out all the magic. People like magic, they miss it.
> Go is a useful language, but it's a language that has purposefully stripped out all the magic. People like magic, they miss it.
I agree with everything you wrote except this. After 3 years in a job where I had to use Ruby on Rails, I am utterly tired of "magic" and I regret the many hours of my life I have wasted debugging issues that were created/concealed by it. Lack of magic is a feature in my opinion. But as you said, that's all this is - opinions.
I find Forth, Ruby, Elixir, various Lisps, etc. almost impossible to reason about because of this. Powerful metaprogramming tools can lead to really hard to understand and hard to refactor code.
Refactoring is the worst part, so bad that people just don't do it. This naturally leads to very convoluted code bases. Ugh. Never again.
And actually, this is another place Go shines. Refactoring Go code is easy because the compiler helps you along. There's even standard tooling that automates some of it. Amazing.
Level 1: let interns use Go(-karts), like their parents did with Basic.
Level 2: most languages. Proper training required and you still have to be careful.
Level 3: C, C++, critical code, kernels, crypto code. Training a commercial airline pilot takes years; and while this stuff is not hip enough for some, there's plenty of demand.
C programmers should be held personally accountable for the damage they cause.
Now of course everybody makes mistakes, but if you deliberately choose C when there are better options available then you should pay out of pocket for your buffer overflows and 0-day exploits.
Yes, I think there are a lot of parallels between high performance cars and high performance languages. Both are held in high esteem and are frequently mis-used when a more balanced vehicle would do better.
The thing that makes java pleasant is large open source ecosystem around it + IDE quality (meaning mostly refactoring and code navigation, especially when compared to dynamic languages). Frameworks like spring or hibernate etc are mature enough and old enough, so there is a lot to learn just by reading.
The language itself makes it easier to figure out what large code written by somebody else was mean to do - not that everything would be readable nor anything like that, but easier then say ruby or javascript.
> Go, however, is like a Toyota Corolla or a Honda Civic.
The only problem with this argument is that everywhere - even in this thread - there are people saying that Go is a joy to program in. It's not lacking magic, it's magical in its own right.
A better car analogy would be that Go is a Lotus Elise. It's nowhere near as powerful as your friend C++'s Mustang or Rusty's McLaren. But to C++ and Rusty's dismay Go's little Elise still gets around a racetrack crazy fast. It may have a smaller engine but it's just taken a really different approach to going fast which works really well. And Go has a much more pleasant time getting to his destination than C++ and Rusty do.
>>>> Go, however, is like a Toyota Corolla or a Honda Civic.
>>The only problem with this argument is that everywhere - even in this thread - there are people saying that Go is a joy to program in.
Not sure why it's a "problem". I love driving my 2004 Honda Civic, and prefer it to newer, fancier cars. It's fuel-efficient, drives very well, and has not given me an ounce of trouble. So yeah, the comparison to Go seems very apt.
Using a similar metaphor, I'd compare Go with a jet that's high performance but easy to fly - i.e. it doesn't have the numerous gotchas and quirks high performance jets usually have that the pilot has always have to keep in mind to avoid shooting themselves in the foot (aka making a hole in the ground :)).
E.g. it won't let you overload your engine by using a very special feature that lets you get away with it, but it'll let you fly fast and enjoy afterwards how trouble free the experience was.
Some languages get in my way and slow me down as a developer. For example I'll always pick Ruby over Java if I have to deliver something quickly. However some languages get in the way of the CPU and slow it down and if that's important I'll pick Java over Ruby.
So both Ruby and Java can be good or bad languages depending on the use case. Some languages make both the developer and the CPU lose time so I won't say they are good.
I have no first hand knowledge of Go but it seems it's fast so it should be good at least where the CPU matters.
Do you have an example of the community celebrating mediocrity?
My impression is of a community willing to go without some features, in order to preserve those it values. Namely simplicity, explicitness, terseness, and consistency.
Explicitness and terseness seem a bit at odds - I wouldn't call go code very terse at all. It seems verbose and repetitive. Consistency? Aren't only some built in types blessed with generic functions?
Mediocrity? The preference for writing loops over simple maps or folds is a bit mediocre. IIRC in Tim Sweeny's "Next Mainstream Programming Language"[1], he notes that around 90% of all the loops in Unreal are folds or maps. Maps and folds are just simpler than loops, without even appealing to terseness and elegance.
Hey I know I'm in no place to judge -- the creators of go and Google overall have accomplished more than I'll ever do. I just really cannot grasp the mindset and penchant for unexpressive languages.
Thats not a strength of Go. Structural interfaces, channels and performant M:N green threads are its main strengths, and AFAIK there is no other language that provides a similar combination in a familiar C/ALGOL-like packaging.
If such a language existed and had generics and Swift or Rust style error handling as well as some backing by a large-ish corporation / organization, I think that language would be preferred to Go.
More expresiveness isn't always better. Examples that hit the sweet spot are C# / Swift (C# really needs algebraic data types). Beyond a certain point, you will start to lose users. Haskell is very expressive, but few will ever have the time or patience to learn enough to build their perfect monad transformer stack and take advantage of the mtl typeclasses to easily use it. Even though it does have M:N green threads, channels, STM and everything.
In fact, Haskell could probably compensate for this and beat Go by having excellent library documentation and well written, focused tutorials for the working engineer.
I feel like maybe 10 years ago no one would utter something like "C# needs ADTs" because they didn't have mainstream appeal, despite computer scientists' understanding of them.
The loop and map are equally readable, it is just that some people are used to one form more then the other.
More importantly, how many character needs to be used for simple idiom like that has zero influence on how maintainable your system is going to be few months later on, how fast it is and so on. The difference between loop and map wont make you do less or more bugs. It may make you read the code few seconds longer first time you encounter form you are less used to - but then you will adjust and read it just fine.
Functions are trivially composable, while imperative loops are not. The difference that makes in terms of maintainability and readability of non-trivial applications is hard to overstate.
Writing code in terms of small, composable, reusable functions with a clear single intent (through good naming), that you can then mix, match, and reuse to compose into larger functions is what makes good functional code so much easier to write, test, and reason about than imperative code.
The presentation makes heavy use of JavaScript and the RamdaJS library in its examples, but the concepts are universally applicable to any language with the necessary functional programming primitives. It also does a great job of comparing imperative and OO implementations of a solution to a problem vs the functional implementation. I highly recommend taking a look if you're even slightly interested in why so many people are starting join the functional programming bandwagon.
So what I'm trying to say is, it's not just a matter of readability. Although if anyone still wants to argue that imperative looping is anywhere close in readability compared to functional composition for non-trivial cases (think multi-level nested loops vs composing multiple functions), then we should just agree to disagree since I don't foresee that becoming a productive discussion.
"Writing code in terms of small, composable, reusable functions with a clear single intent (through good naming), that you can then mix, match, and reuse to compose into larger functions is what makes good functional code so much easier to write, test, and reason about than imperative code."
Absolute, that holds for non functional code as well.
It just does not matter whether the smallest function inside that system of functions has a loop or a map inside it. Loops are as easy to tuck into reusable functions as maps or anything else. Notably examples in the presentation you link have functional version shorter, but harder to read - they have more features however. Even the first one pipe(..., reduce(add, 0)) just does not read fluently.
But again, this low level has very little influence on maintainability of the larger program. In anything that is not computational library, how you compose them matters more. It is as if you assumed code with loops can not be split into smaller composable units.
I worked with codebase written in largely functional style. It was hard to read at first, but then I got used to it. However, it never became all that much easier to read them loops nor easier to work with. It gets bad when people get clever with composing functions.
> It just does not matter whether the smallest function inside that system of functions has a loop or a map inside it. Loops are as easy to tuck into reusable functions as maps or anything else.
This is certainly true! You can definitely wrap all your loops in functions that take in a collection as argument, and return another collection or value, and as long as you don't produce any externally observable side effects with your loops, these functions are as good as any other as building blocks of a functional program.
Consider the age old adage: "If a tree falls in the forest and nobody hears it, did it actually fall?", similarly, "If a function mutates some internal state only visible within its own scope (a counter or accumulator in an imperative loop, for instance), did it actually mutate anything?" The practical functional programmer would answer with a resounding "no". In fact, RamdaJS itself is implemented mostly imperatively internally for performance/compatibility reasons, but exposes a functional API for the consumer. Similarly, Clojure is implemented the same way for many of its core functions, and exposes an easy way for users to perform mutations for similar purposes within the functional, immutable-by-default language using transients: https://clojure.org/reference/transients
If you use imperative loops by wrapping them in this way, however, note that you're essentially implementing the same function signature of a function that calls map/filter/reduce on a collection, but with imperative primitives, and that's definitely a valid approach. If you build your programs by writing and composing these kinds of functions, you are in fact doing functional programming, and can reap all the composability, maintainability, and testability benefits that come with it.
I don't think there's any room to debate that most developers don't use imperative loops in this way, however. And my point was that the way they're usually used was not trivially composable. Of course, you could always refactor them into small functions that are trivially composable, but that they need to be to become composable is why I prefer using trivially composable primitives like map/reduce/filter to implement my programs as a default, and optimize specific functions with imperative implementations on an as-needed basis after profiling and identifying all the critical paths (premature optimization, and whatnot).
RE: `var sumOfSquares = pipe(map(square), reduce(add, 0));` not reading fluently.
This is where we'll have to agree to disagree. To me that reads quite literally as "given a collection, return the square of each item, and add the result of each to the next, starting from 0, to return the final value". The functional approach could definitely look more intimidating to readers without any general knowledge of functional primitives and what they do, but that's an issue of familiarity, rather than one of inherent readability.
Yes, people can get crazy with nesting multiple inline composed functions inside of other inline composed functions on one insanely long line, and that can quickly get out of hand in terms of maintainability and readability, just as people can get crazy with nesting loops. But that's just a case of bad functional code that needs to be refactored using a composition of smaller, well-named functions broken down into multiple lines. Nobody is claiming functional programming is a panacea for bad code.
It is not necessarily easy to recognize when a loop is a map or filter -- I think that's the issue. It's why someone like McSweeney would bring it up.
The Python approach -- where maps and loops share a lot of syntax -- is maybe the middle way. On the one hand, it's not an approach that gives rise to `.map()`, `.collect()`, `.flat_map()` and so forth; on the other, it's marked out as something returning a result.
I dunno, ruby has some nice tendencies here, like `out = [1,2,3].map(&:to_s)` which is small and descriptive[1].
Compare that to:
out = []
[1,2,3].each do |x|
out.append(x.to_s)
end
IMO that's not fad material - that's progress. Maps and folds can totally be abused to produce inscrutable nonsense, but for small, common operations they're often much more obviously-correct.
[1]: `&:method_name` is extremely-common shorthand for "call this method"
It does though. Maps and folds - and functional programming in general - focuses on the /what/. For-loops on the other hand tell the compiler / cpu the /how/.
Summing is a nice example. A naive for-loop will just iterate through the list, keep a variable around, add the next item in the list to it. In functional programming (or with a reduce), you tell it to sum in a more concise way - but more importantly, you don't tell the compiler how exactly it should do it. It's trivial with functional programming to make the task (for example) multithreaded or to use advanced underlying cpu tricks, without you as a developer needing to know how exactly it does what you ask it to.
Consider product as a counter-example. With an imperative loop, it's easy to add an early-out condition if
zero is encountered. But this is harder to do in a (strict) functional language.
This is exactly why lazy evaluation is often described as control-flow. Lazy evaluation permits efficient composition, without doing extra work (although the constant factors become much larger).
Yes, that's exactly right. And Go takes a relatively strict stance on making the _how_ obvious to the programmer. It goes out of its way to avoid hiding O(n^k) loops behind language sugar like map or fold, for example.
You can hide a loop behind a function call in Go, Python, really any imperative language.
What makes map different is that it separates the looping mechanics (incrementing, initializing and appending to the collection) from the actual computation we want to perform on each element. It's just separation of concerns.
Yes. In Go, function and method calls are the primarily, perhaps only, mechanism of abstracting computational complexity. That is, when you see a function or method call, you know that "anything goes" back there, and you need to dig and find out what the computer is gonna be doing. Pretty much everything else is implemented "in plain sight"; in the case of fold/map, that means with a for loop, where you see precisely how many iterations you're going to step through.
You're right: map separates looping mechanics from computation. In Go, that's a bit too much obscurity.
The argument for maps and folds is the same as the argument for structured programming in general: using common/reusable idioms brings clarity and familiarity.
It's the recognizability, not the terseness, that brings clarity.
Although Python's approach is not terse -- `fstyle = [f(x) for x in arr]` -- it is eminently recognizable.
Your argument is not really about anything I specifically said; and without something to counterbalance, it argues against structured programming, too.
My argument is that "recognizability" is in the eye of the beholder. One programmer's "map is a powerful abstraction over transforms, for example loops" is another's "this is some cutesy code/math creole by a CS graduate who desperately wants to find nails to apply his functional programming and applied math hammer on".
That's a fairly harsh way of saying that at some point the abstraction isn't clarifying, whether it's recognizable or not.
Disclaimer: I'm a big fan of functional idioms (they're one of my favorite parts of Rust, for example). I'm not so much a big fan of absolutism or over-generalization.
No, maps are conversions between types containing other types. Maps are much more powerful than just doing something over an array in languages that support a functional style.
Java reigns supreme because there is nothing which come close to its characteristics in terms of capabilities, libraries supports, tooling, performances, easiness to learn, simplicity and maturity.
If you want faster or lower level, you gotta move to C++, which is uber-hardcore in terms of non-simplicity and impossible-to-learn.
If you want easier, you gotta move to python/ruby/node.js, which are a joke in terms of performance and concurrency, with the last 2 being fairly young and immature (< 10 years).
Either way, the tooling sucks compared to Java, if not entirely non existent.
Entreprisey development is on Java because that's what best for them. Web development is on something else because they pick what's cool and trendy.
Once you know whatever java framework well enough and your project is not something ruby on rail spits out immediately, shipping fast is not a problem. In 4 months timeframe, you can definitely produce more or as much as with node.js or something like that.
The issue is that you wont do good frontend in it (obviously), java programmers are more expensive, learning it well enough so that you can actually be that fast takes a lot of time and hosting is way more expensive. Learning language itself is easy, but absorbing necessary frameworks takes time. Moreover, people who are good in frontend prefer languages similar to javascript, because they already know it very well so those are easier to learn for them.
I think this is why it does good in enterprise - they have money to throw at hardware, most projects are under huge time pressure constantly and requirements change constantly. Frontend is super important for product, but not so much for enterprise.
Ide makes learning easier and faster instead of harder. You dont have to care about compiler passes, ide compiles seamlessly.
But yeah, learning java ecosystem well enough takes a lot of time for someone who is just starting and you have to be comfortable with abstract thinking.
"Good" and "bad" aren't really useful descriptors without additional context. And what do you mean by "mid-quality" developers? That seems gratuitously insulting.
I think simplicity is often the most difficult to achieve and requires deep technical expertise to deliver. It shows the creators have thought about the end user and usage scenarios. It would be a mistake to confuse complexity with quality or vice versa.
IMO the Go goal is to be an enhancement of C. It is not as expressive as some existing languages (i.e., Go programs may be longer), but it is very good for translating clearly thought through logic into efficient machine code.
It supports some of the features that original C lacks (networking, parallelism, channels, etc.), which to me is a very good thing. With minimal forethought this allows writing programs that can be massively scaled later without impeding initial checkouts at small data sets.
Eventually the success or failure may be determined by the libraries developed by the user community. For example, fortran survived so long not because it was a good language, but because it had freely available, easy to use world class libraries for numerical computation. Many grad students kept using Fortran given the choice of an existing, working, ugly-ish code that they could use for their PhD projects vs redeveloping and retesting the same functionality from scratch.
In my experience writing go is very fast and reading go is also very fast. The language was designed to be very comfortable, and they did a great job with that. You sit down to write something and you don't have to think too much about the best way to tackle the problem, the lines of code just flow from your fingertips. There's mostly one way to do everything, which makes doing things easy.
The legibility and simplicity are my favorite things about Go. I know that I can fearlessly dive into other people's source to figure out what's going on without running into 15 levels of indirection hell and a bunch of language features/idioms that I'm not familiar with for one reason or another.
I feel the same. Go is a different type of terse. I think terseness goes beyond the number of lines. When I skim Go code, I can grasp the meaning of it very quickly.
I've seen talks where Rob Pike describes Go as being "light on the page" vs. "noisy", meaning (I think) that it doesn't have lots of sigils and annotation bits around the code.
I really hope not, there is already a lot of awful code around written in Java.
I can't imagine codebases on the MLOC range written in a language even worse than java 1.4 (it didn't have generics, but at least it had exceptions)
"bussiness" languages will never change. It will be Cobol, Java, C#, Go, and then something like that in the future.
The truth is, theres not enough smart people to do things in the hundreds or thousands in a more sophisticated language.
And also speaking of smartness, sometimes, using simple tools, can help you focus on algorithms. Linus and crew coded the whole Linux in C, a language with very few resources, and considered pretty ugly by today's standard.
So i can see the beauty of that, even when you are able to use any sort of more sophisticated language, sometimes chosing something that can be shared with more people can pay off, instead of a more "elitist" language, with a higher barrier of entry. And also lets not forget, that theres always some economics at play. Where companies not focused in IT will choose tech that can scale by the number of employees, do its job and be cheap as possible.
I think there will be no antidote for that. It will always be some reincarnation of Java.
Libraries may be a stumbling block for Go, though, because C interop is somewhat slow. Photoshop, Python, Postgres, &c are not all likely to support plugin/extension interfaces based on Go calling convention anytime soon.
I'm concurrently learning Go and Node, which might not be a fair comparison but I'm going to make the comparison anyway.
Node feels like a flesh wound with delicately layered bandaids. The ecosystem is a mess, you have to jerry rig basic packages to work together, the syntax and semantics of closures and context is ridiculous, and despite that callback mania is like this cool-aid that's supposed to feel great once you drink it (but hasn't yet for me).
Hehe, I have to underline this aspect as npm killed half an hour of my work yesterday, when I redownload some package in a sibling directory (for diff purposes).
Never had this experience with go. The comparison is a little emotional for me, but when I realized npm just killed my code, I was emotional...
Nevertheless, Javascript/Ecmascript is the result of years of development in a living environment (the web) while go was designed from scratch, by some of the most capable programming language designers on this planet, to enhance their previous work. Who wonders about the result?
My impression is that Go is a language that was cobbled together to simplify the coding of some specific applications, such as simple servers. It lacks any kind of purity, is not the best choice for any specific task, but is just good enough for some (many?) tasks. And poor type safety!
Frankly, I can't help being disappointed by how bland this language is, and I have zero interest in using it. Maybe because I like coding, and the IMHO using Go or Java would totally kill the fun of it.
To each their own. I enjoy writing Go almost as much as writing Python. But more importantly I find reading Go easier than any other language - mostly due to its explicitness and consistency between authors. That has made it much easier to dig into code bases that solve some very complex and interesting (to me, anyway) problems.
Also, I assume the 'no type safety' statement is just hyperbole?
Or maybe they mean that you HAVE to use interface{} for any reasonable kind of generics, such as developing generic data structures, or generic handlers for RPC interfaces allowing arbitrary nesting?
I've always believed that blandness is the reason why the language was created.
Google has a ton of developers working on a giant codebase. If Google were written in something interesting and complex (eg scala or ocaml) then some parts of the codebase would be remarkably complex while others would be simply a ton of library imports and then something procedural. Whether you are in the former or the later would be developer dependent.
Now, say you're a Google exec, you know you're losing a ton of developer hours as people ramp up to different parts of the codebase and that some parts are so complicated that only a few (expensive) engineers could ever work on them. The more you can remove differentiation between engineers and commoditize programming the less expensive specialists you'll have to deal with and (hopefully) things will get cheaper. There's a size at which the investment in creating a new, bland, language will pay off for you - hence golang.
Heh, it does feel repetitive. But after ~10 years with Java, I'm happy to avoid the cognitive load from deciding how to most politely generate/propagate an exception. Obviously, there's no perfect solution, and preference is subjective.
In reality Go makes it worse, if you truly keep track of all possible cases. After calling a method, in Go you have to
1) "if err != nil" after every statement
2) give some serious thought to whether the previous statement could panic or not
Good luck if it's a library call that may get updated or call other libraries !
3) Think about the non-error error cases that can't be abstracted out. Go is like C, in the sense that there is an ERETRY "error" (unsurprisingly, you should simply try again, you should NOT fail)
And there are cases where there can be an error and yet error is nil. Easy example of this would be sscanf.
And we now see practical Go code published online : how these problems are dealt with, real world edition:
1) either mindlessly putting "if err != nil { return err }", which is a very bad information-erasing exception system, or just outright ignoring errors. Don't you know you can also use "_" as the error variable ? Maybe they should make that implicit like in perl. Of course perl is likely to tell you this happened ... unlike C and Go.
(really brings back the C days doesn't it ?)
2) most people either don't know or just deny this. Thankfully panics at least do list where they occur. They also kill your program and print stacktraces. Pages and pages and pages of stacktraces.
3) very few people even know about these problems ... so they're ignored, and the standard Go tools themselves don't behave according to unix specifications.
Panic is pretty much never used (so you don't really have to think if the previous statement can panic. If it does it means something is SO wrong that your application can't continue anyways because it's broken)
You should really use a library like github.com/pkg/errors so you get to wrap the error you return with additional information. Errors are just a worse Either monad after allm they're much more pleasant to use than exceptions.
> Errors are just a worse Either monad after allm they're much more pleasant to use than exceptions.
How are errors in Go at all monadic? They just have a convention where you return a tuple and manually check if something isn't nil. Either type will inhabit one variant or another, not both with one having a value of nil.
The 'monadic' part of Either (or Result in something like Rust, where try! is sort of like >>= if you squint) is the ability to chain Either types together and have the boilerplate abstracted, that feature is completely absent from Go. Errors in Go are neither the Either type nor monad, IMO.
As I said, in practice they're a worse either monad. With which I meant -> they were inspired by them, but lack the monad part and having the value with the error in one object interchangeably. It's the same treating errors as values though.
It's really just a worse Either type, if anything, there's nothing monad about it. Although it's sort of hard to be close to an Either without being an algebraic data type. But I see what you're trying to say.
> Panic is pretty much never used (so you don't really have to think if the previous statement can panic. If it does it means something is SO wrong that your application can't continue anyways because it's broken)
That's it. I think OP just assumed panics in Go are what exceptions are in other languages.
Because the stdlib is using them more and more? As someone mentioned, even closing an already closed channel can panic. Calling the random number generator with a negative limit panics.
And there’s nothing like checked Panics so you’d know if one will happen or not.
As I said, if your code is plainly wrong then I see no problem in it going haywire. The channel rules are widely known -> you know, it takes more than a few days to learn a language, there are a few rules to learn too.
Calling a number generator with a negative limit is also a programmer fault, so no reason to provide an error here.
I see nothing wrong with that - those _are_ fatal conditions that indicate that something is dangerously wrong in the program.
And those panics do give you a helpful stack trace, complete with source code line numbers, so it's easy to find the culprit (as opposed to "bubbling up" exceptions).
These uses of panic look a lot like the canonical use of unchecked exceptions in Java: the programmer has made an error, which they could have avoided. It's a bug. There's no point returning an error and letting the program try to recover, just blow up with as much information as you can, so the bug can be fixed.
The canonical use of checked exceptions in Java is for unpredictable events - almost always related to interaction with the outside world, like IO, networking, parsing, etc. These are things the programmer can't prevent, and must defend against, so the type system allows, and in fact forces, the programmer to explicitly address them.
This is all explained beautifully, and at length, in this monograph:
> There's no point returning an error and letting the program try to recover, just blow up with as much information as you can, so the bug can be fixed.
Well, imagine a game letting the user roll a dice. "Chose a number of sides for your dice".
In such cases, handling such a panic might be useful. And knowing that it exists might be useful, too.
If the language does not allow specifying a range of a type (for example, requiring all numbers passed into the RNG to be positive), then it should be specified in the API in other ways programmatically, so it can be statically analyzed.
As I said above, panics should ideally never be able to occur, but be part of the type system.
In languages with dependent types, for example, it’s common to represent a Stack in a way that number and type of elements are stored in the type (so you can’t even pull from an empty stack – that’d be a compile time error).
In the same way, the random number generator should either return an error, or use a number type that can only encode positive numbers as input.
Especially if combined with the interface{} everywhere across the new stdlib functions this all smells very much like C's problems.
Not really. In a language like Java, some of the questions I'd have to ask myself are:
- Should I try to catch the exception, or just let it
bubble up and edit my interface to include it?
- Should I create a new exception type or reuse an existing one?
- Should I throw a checked or unchecked exception?
- Am I exposing implementation details via my interface?
(eg I don't want to throw an SQLException from GenericDataSourceWidget.connect())
In golang, I know there's really just the one pattern: check if err != nil, prepend a descriptive message, and return it.
>check if err != nil, prepend a descriptive message, and return it.
That'd be the RuntimeException equivalent, sure. But what do you do for the equivalent of checked exceptions? Errors are frequently recoverable, "err != nil" alone does nothing to help you there, and string manipulation is a horrific alternative to types.
At which point you're back to the original complaint of:
- Should I try to catch the exception, or just let it
bubble up and edit my interface to include it?
- Should I create a new exception type or reuse an existing one?
- Am I exposing implementation details via my interface?
(eg I don't want to throw an SQLException from GenericDataSourceWidget.connect())
(except for "- Should I throw a checked or unchecked exception?" since that's fairly Java-specific)
To me, those questions seem unavoidable, and sweeping them under the rug is a false simplicity. You're exposing things - what do you expose? How should the caller deal with it? Is it the same as [other thing]? I'd much rather have the type system involved, since error handling is pretty critical to correctness/stability. If go's giving up the safety, what does it get in return?
I feel like the type system is involved? If there's a problem it's that Go doesn't make throwing typed errors a common convention (and we lack the tooling to make handling them a habit I.e. inspect this call and find me all the error types which can come back.
It's used very heavily for everything container related. It seems to be an excellent fit there, at the very least. It's also becoming an increasingly popular choice for startups when they need performance, which used to be something Java or C++ were typically used for.
Personally I've had a lot of fun using it, but prior to starting with it I'd mostly done Java and Node, so that may have something to do with it.
I'm not convinced that using startups as a metric for anything programming related is a good idea. At least not startups here in the Bay Area, which seem to me to be very fad driven.
Today's startups are tomorrow's huge stack of legacy software that Nobody Wants To Touch Because It's Our Core Business though; I'd say Go is a pretty good choice for those due to its simplicity and shunning of 'clever' code. Companies like Paypal, Ebay, and probably a few others have (had?) a huge load of old Java code and only recently spent a lot of time cleaning that up (iirc Paypal went with Node, at least for its forward-facing things)
I don't know how maintainable 10-year old Ruby code is though, on the other hand.
Today's startups are, mostly, tomorrow's failed businesses. The majority of the most successful startups of the last 15 years have generally used tried-and-true battle tested technologies in their successes: Java, C, C++ and PHP.
This isn't to say Go doesn't belong in that list, but simply to reinforce my point that what startups are using today shouldn't be an indicator of high quality technology that can (or should) gain more traction and use in the future.
And Ruby. Ruby is basically the new Java. As in it's no longer cool but is considered battletested and is now at the core of 10+ year old companies with code bases just as old that noone enjoys working on anymore.
That may be, in which case Python belongs in the same bucket. I'm not convinced, actually. Most of the "ruby shops" I know use it only for the most trivial of applications, being essentially rest-like proxies between clients and Java (or other language) services. But I don't know everything and anecdotes aren't data for sure.
That is a good point, and it definitely is. But in this particular case I think it makes sense, although there's probably a "shiny" factor to it as well.
Snarky, but its such a tiresome argument. If you need something Go does not supply, use a language that fits your needs. There are a lot of programmers happy in Go, and thus happy without generics.
There are programmers who are happy using generics, thus write in Rust, Java, etc.
By copy and pasting or code generation, as we've unfortunately had to do. Makes for messy things like DateRange paired with DateRangeInterval tree vs. a generic Range that works with an IntervalTree.
That's just a jailed process. There's no reason to need a completely different language, especially one without any specific support for running untrusted code.
They seem to take a lazy approach to feature development. Generics are complicated and bad, but having makeIntMap or makeStringSlice is...not great for developer productivity.
So let's special case `make()`, slices, channels, etc. so that some productivity is possible.
Then as they add library features they violate their own tenants as they find utility in these verboten constructs. Exceptions are bad...But we have panics which are in no way the same thing renamed. Never expose them outside a package...But closing an already closed channel panics. Random number generator functions panic on mundane and expected things, just like Java checked exceptions.
```
The convention in the Go libraries is that even when a package uses panic internally, its external API still presents explicit error return values.
```
It's just an inconsistent and, quite frankly, disappointing language outside of goroutines and its interfaces. Those two make it possible to be productive, but with generics for instance a whole slew of new possibilities will emerge.
The simplicity is nice, but it's too simple and too inconsistent. All the verbosity of Java combined with the impenetrable inconsistency and abbreviations of C.
I wonder this too. For how important generics are claimed to be, it does seem strange that nobody has stepped up and helped out the core team in this capacity. They have been quite open about wanting generics, but do not have the resources to dedicate to implementing them in an acceptable fashion. But being an open source project, anyone can step up to fill that void.
I don't know, but Google does frequently complain about not being able to find talent. Some of this is through fault of their own, but it is easy to imagine that they have not found suitable developers to fill the spot, for whatever reason it may be. They have lots of other business goals for what developers they do have. Putting their people on generics at the cost of some other business function may not be a good choice, even if it is theoretically possible.
I've been thinking about a two way compiler with a primary focus on producing readable code. If such a compiler targeted Go or Java, you could white your "Go+" code (for lack of a better name) in a higher level language with more features, and have it compiled to readable Go code. I don't know to what extent this is possible, but if it was good enough you could be a Go developer while rarely writing actual Go code.
You can have your generics and many other nice things combined with the gccgo goroutines, channels and garbage collector by switching to Nim: https://github.com/stefantalpalaru/golib-nim
It's a balance, but I am fairly disappointing that such an up-and-coming language has such a limited type system.
In the days where even traditionally fully untyped languages are moving toward inferred, optional and static typing [1],[2],[3] I'm disappointed to see `interface {}` sprinkled throughout Go API's.
Go's blandness is a feature to me. It's not a joy to write but pleasant to read and understand which, sadly, won't matter unless Golang gains more popularity.
I've actually been very surprised at the near-ubiquity of Go in the modern infrastructure/tools space though. Seems like each new OSS product I evaluate is written in Go. See companies like Cloudflare, Hashicorp, InfluxData, CoreOS, and, obviously, big projects like Kubernetes.
I think that's mostly because Go trivially generates static binaries, and cross-compiling is also trivial (as long as you don't use CGo).
I can't actually think of a single other language that matches that. Rust might get there one day but cross-compiling still requires a C cross-compiler (ugh) and C dependencies (e.g. OpenSSL) are often dynamically linked.
Not a C compiler, but you need a C linker, which is just as much hassle. Apparently there is work going on to use LLVM's lld linker, which I guess might support cross-compiling in a sane way but I haven't checked.
And yeah most wrappers provide a static linking option but there's not much consistency which is rather annoying.
Go is meant for distributed systems. All these companies, and generally speaking a lot of infrastructure thing is in that domain. They use the right tool for the job.
I don't disagree about the type safety and general qualities of the language, but saying "Maybe because I like coding" is really unnecessary language egotism. There are many, many people who love coding and love doing it in Go.
Personally I like Go; it's a very fun language for me. It's true that it sometimes feels like a language designed for the precise purpose of writing daemons, but that's exactly why I like it.
The thing about Go is that its opinions on concurrency are ones I share, to the point where I was practically waiting for something like Go to be invented.
Other than say, Erlang, I'm not aware of many alternatives which provide
a) ultra-cheap coroutines (10,000 coroutines? fine!),
b) an I/O system which is seamlessly integrated with that concurrency system (and in a totalitarian manner at that; if you're using Go, you're using its event-based I/O scheduler, no exceptions), and
c) a rock-solid runtime.
[IO SYSTEM.] The imposition of Go's I/O system is important, because it means all Go code is written using the same I/O system, which makes code reuse much more feasible. The chances of you being able to integrate a random OSS library that you discover in say, C++ into your C++ project is much lower:
I call design decisions that pervade every line of code in a project "cross-cutting considerations" (CCCs). These are design decisions where changing your mind means rewriting every line of code, or at least reviewing every line to see if it needs rewriting. Your ability to consume a library depends on where your project and the library sit in CCC-space, an n-dimensional space. If your project is written using an asynchronous I/O reactor, and the library uses a traditional synchronous, sockets-based programming model, you're screwed. You can't use that code, unless you maintain a fork (and in that case you'd have to transform the library into the continuation-passing style, etc.). If the I/O is pluggable, you have to go through the effort of plumbing it into the reactor library you've chosen to use, just to be able to consume that library.
Not only does "using Go" imply the I/O system that goes with it, Go's tightness in language design means you don't see the feature rejection that you see in a language like C++. C++ isn't a language, it's a family of languages; everyone chooses their own subset of C++ to code in. Some people think exceptions are bad and avoid them, and some people think templates are bad and avoid them, etc.
What this means is that the statement "this library is written in Go" is a hell of a lot more meaningful than the statement "this library is written in C++". It's not just C++ either; Python for example now offers a wide variety of choices for I/O, which inflates the CCC-space across which the language's ecosystem of libraries are distributed. One library could use asyncio, one something Twisted-like, one synchronous calls, one threads, etc.
[COROUTINES.] It's the right way to do concurrency. Not the continuation passing style; it's truly preposterous that programmers have been made to write in a format originally intended to be implemented as a compiler transformation. Only recently are we seeing languages augmented with async/await keywords to allow this transformation to be performed behind the scenes (JavaScript, Python 3, C#). Erlang has been around a long time making the CPS look ridiculous, and later there was Stackless Python, an ignored gift horse to the Python community. Stackless Python failed to be a real alternative to Erlang, Go, etc. because it never managed to get a thriving ecosystem or IIRC, a standard I/O system around it.
I also perceive that Go has almost completely accidentially obtained some additional fondness for the fact that it produces statically linked, portable binaries. If you're shipping only Go code, you may often be able to get away without using containers when they'd otherwise be essential. You see Go binaries for Linux being distributed officially by OSS projects when normally for Linux that's very rare; it's left to package managers, and you have distro differences making compatibility potentially tricky.
The fact that Go shipped with a standard, configuration-free build system also makes creating new libraries, or bringing in existing ones almost completely frictionless. Even if you think Go is boring as a language, what really makes it stand out is its execution. Just look at how they're improving the GC with every release.
(This turned into an essay... I guess my ultimate point is that getting a coroutine-based highly-scalable I/O programming environment to work as an ecosystem requires you to standardize on one runtime completely and utterly, and be able to trust that runtime with production workloads. The only such systems I can think of which are stack based and which formed successful ecosystems are Go and Erlang; though now we're seeing a lot more CPS-based systems using async/await annotation, which are probably more than good enough for the same applications. Although I would point out that neither Python 3 nor JavaScript are trying to occupy the multi-thread m:n scheduling space in the same way that Go and (I think?) Erlang are. They're constrained to essentially single-thread operation.)
> Other than say, Erlang, I'm not aware of many alternatives which provide a) ultra-cheap coroutines (10,000 coroutines? fine!), b) an I/O system which is seamlessly integrated with that concurrency system (and in a totalitarian manner at that; if you're using Go, you're using its event-based I/O scheduler, no exceptions), and c) a rock-solid runtime.
What language is pure anything? Even Smalltalk wasn't pure Objects. Programming languages are pretty complex. If you look deep enough, you'll find the leak in the abstractions.
ouch compile time type safety... even Go maintainers have abandoned it. Go pundits can't expect developers not to do the same thing in their own codebase at that point.
The ability to provide inline comparison function for Sort() is welcome. It's one of those infrequently needed language niceties that have (at least for me) made perl and python so slick to use.
Sorting arrays of objects or small hashes, based on arbitrary properties/keys, is quite useful.
You are not really responding to the comment you are replying to, though. Yes, being able to do custom sorting is nice, but no-one challenged that claim. The type system really doesn't look very nice when it won't even manage type safety in such a simple case as this. Also, compared to other languages that is in sort of a similar spot[* ], such as Swift or Crystal that both manage type safe custom sort functions, it looks even worse.
[*] That is, modern languages that compile down to native code while having some basic way of avoiding manual memory management.
On the one hand, I really cannot stop using it. I can build an small web applications in a day or two, I can write them in just slightly more lines than Rails, and the applications I can build are much speedier than Rails applications.
On the other hand, I really, really hate using Go. It's tremendously boring and I never feel the code is that elegant.
I've tried Haskell, but I end up messing around monads too much because there's so much IO.
Rails is fantastic, but I'd prefer to experiment. I never grow as a developer when I use Rails.
Node.js is great. But if I don't need to write a lot of JavaScript on the frontend I end up asking myself: why am I writing JavaScript on the backend?
Racket or Chicken Scheme look like good directions for me. Erlang looks interesting. Maybe I should give Clojure another shot?
Your comment is similar to how I feel about Clojure. It's "good enough" for me for most things. Whenever I need something fast, that's what I grab for first. But, it feels "mushy" after +10k lines of logic, and I'm wishing it was F# or Haskell. I think I just need to bite the bullet and only use Haskell from now on. If it's slower at first, meh, it'll catch up when it grows.
Completely unusable, perhaps the worst in recent memory of any front page article. Strange thing is that previous Go presentations have looked almost identical aesthetically but worked well.
I'm not sure what your exact requirements were, but I immediately thought of the following:
* Beamer: write slides in LaTeX, maintainable for a long time to come and easy to build.
* Reveal.js: use JS and HTML to author slides, easy to present, and pretty maintainable I think.
* Pandoc[1]: use Markdown or RST to write your slides, then compile to HTML (e.g., Reveal.js) or LaTeX (Beamer).
* Google Slides
I'm not sure if any of these (except Beamer) were available back when you wrote the tool, but given some of the complaints in this thread (e.g., not mobile-friendly), wouldn't it make sense to migrate to some other tool going forward?
[1]: Absolutely fantastic tool all-round, and written in Haskell to top it off. I used it a few years back to write a LaTeX report in Markdown. It's definitely not as good as writing LaTeX directly, but it's a great place to start. I can't praise Pandoc enough.
Reveal wasn't a thing when I wrote present. I probably would have used it as a front end, had it existed.
Tools like Keynote and Google Slides were exactly the kind of thing we were trying to improve upon. They're great for making pretty slides, but a total PITA for authoring and editing technical content.
Can any of those tools execute code from within the slides?
I'm yearning for the Golang of functional programming. That is, excellent std lib, clear documentation, awesome tooling, active community.. and after typing this, maybe that's Elixir? Though I do love static typing.
They have an active community that is very engaged in improving the entire developer experience. Plus ReasonML is just OCaml under the (new syntax) hood so you have decades of OCaml expertise and libraries to draw on. In case that's not enough, it also deploys to JavaScript and targets the npm ecosystem, so you also have the entire npm package collection at your disposal.
I was thinking about this a year ago & decided on Elixir.
So far I have no regrets. As you mentioned Elixir satisfies all the conditions you mentioned.
For the static typing part, I agree. But since there's no OOP, the flow of the information throughout the app is pretty explicit & the reasoning behind it is easy to be debugged.
I love your Just For Func videos! I wondered if you could make one explaining pointers in Go. No explanation I've found really settles in for me, and while I'm getting a 'feel' for them writing more code and getting feedback from the compiler, I'd like to find a good explanation of them. I'm asking you specifically because you have a really great way of explaining things, and a warm presentation style. Either way, thanks for all you've given through your talks and videos!
Definitely the talk I enjoyed the most at FOSDEM today. Both instructive, relevant and pleasant to listen to. Glad to see things like sort.Slice or JSON rendering. When you're spoiled with python or groovy, you miss them them badly.
I was glad to find they made it much easier to define custom sorts for slices. But! Why on earth does what should really be syntactic sugar make sorting nontrivially slower?
It speaks to the lack of expressiveness in golang that you can't make sorting less egregiously verbose without adding a performance penalty.
They probably use run time reflections, not a compile time syntactic sugar a.k.a. generics. As Go doesn't have those, so anything like that would require a compiler hack and nobody likes hacks.
Syntax sugar is extra syntax to make an existing feature easier to use, syntax sugar has no runtime impact.
Generics are not syntax sugar, they add functionality such as stricter compile-time type checking and improved run-time performance (e.g., C# can use unboxed primatives in generics)
I shall be moving my codebase to Go this year. I'm very impressed at how readable it is, how much thought has gone in to the tooling and support environment and how fast the GC is now. I also must be one of the few people who likes the assembler :)
Most of my work is C++ but I've also used Go a fair bit since Go 1.5. I like Go a lot. The C++ crowd (including myself) keeps trying to make things that are trivial in Go easier in C++ but the best efforts still look like a mess. I think the lightweight/green threads model of concurrency wins over others (threads, processes) and is incredibly difficult to get right in C++. Channels are also very useful and difficult to get right in C++. While C++ with some aid from Boost can be a very safe language it ends up being a lot harder to write and read with all sorts of [](){} -> hacked up conventions that are a result of backwards compatibility. I find the test infrastructure in Go to also be very pleasant and easy to use. Stuff you need to go to extremes of C++ to test are just trivial to do in Go.
Things I would like to see improved:
- Package management. I think "go get" was an interesting idea that is basically a fail for anything except the most trivial of situations. Vendoring is not a great solution either IMO. Perhaps some idea that manages package versions through local git repositories can work better since a git repository is a better representation of the version history of packages.
- I didn't like the compile speed loss we took when the compiler code base moved to Go. I'm not quite sure where it stand right now but one of the things that I liked about Go from the beginning is lightning quick builds.
- In my usage there seem to a few quirks in the language including the various scoping weirdness and the declare and assign operator := ... I frequently end up with code that re-uses the same variable such that the first instance is := and the next are = which makes refactoring a pain. The compound if statement also suffers from this.
The uppercase/lowercase public/private convention is also odd. You get used to it but it seems like a hacky afterthought.
I for one will be more interested in using Go when Jetbrains finishes their IDE. Clearly not everyone cares to develop in an IDE but after 33 years of doing it, I prefer the idea. Give Swift (my current work) as many years as Go has had (10 years), and maybe I won't find Go that interesting any more.
To each their own, but Go is probably the only mainstream language that has first class integration with text editors. So I wouldn't let that stop me from using it, unless you can't see yourself using a text editor at all.
In my Emacs I've got 1) eldoc (displaying signature of function at point), 2) function source lookup, 3) function documentation lookup, 4) flycheck (display compiler err/warn on save), 5) auto-completion. Among a few other things like go-guru integration which I haven't used much yet but I can see its use.
All of those features come from editor agnostic golang tools.
Do they do static analysis of code? The problem is that with other languages they all work "sort of". For example, for Elpy:
"the backends can not always identify what kind of symbol is at point. Especially after a few indirections, they have basically no hope of guessing right, so they don’t"
With go guru it just works, always, no matter how deep you drill into the graph (that's what I meant by "first class").
With C# and TypeScript and all LISPs I've worked with, they work hand in hand with the compiler/runtime to provide absolute correctness at all levels. Absolutely first class. (And I agree Elpy does not qualify for that term)
And while we're on the subject: Only Microsoft had the foresight (or hindsight, insight, whatever) to realize this was a general problem and propose a solution which applies to all editors and all languages:
You'd think Google, with their tons of resources could put together a few resources and join a new, future-proof non-NIH standard for Go, but so far they seems to be lagging.
I agree, a common standard would be good. That said, experience taught me to distrust any proposed standard that comes out of Microsoft. Besides, I find that with the programming editor communities, such standards are not that important - as long as a language has the tooling, it'll be integrated, standard or no standard.
This protocol is about reducing the N languages and M editors = N*M client/server implementations with a much better N+M solution, where we don't have to reinvent 200 wheels every time someone makes a new editor or language.
And the protocol is open. Seriously what do you have to lose, besides a shit-ton of redundant work?
Distrust? Distrust exactly what? Are you sure you aren't being your own worst enemy?
See here for a list of fully open source and MS-independent implementations: http://langserver.org/
The issue there is that Python is a dynamic language. Syntactic resolution of what a "thing" is in, in some sense, not supposed to always work -- otherwise it would be a static language!
Being able to recognize what a syntactic entity represents -- type or value or whatever -- has been supported by the editor plugins for static languages for a very long time.
For sure, but then there are mainstream static languages like Java/Scala which still lack that kind of support (e.g. ensime and friends, which work unpredictably, if at all).
IDE functionality, similar to what godef/guru for Golang offer. But I'd settle on any mostly working jump-to-definition tool for Ruby/Python/Java that can be integrated with Vim/Emacs.
I've been using the Gogland beta for the last few weeks and it's been quite stable. For large codebases, it's hard to beat a good IDE's ability to quickly jump between symbols (go to definition, find usages, etc).
Conversion rules seem like an awfully specific language feature to introduce just to scratch a very particular itch.
The rest of the slides are pretty standard-fare, and that's a good thing. Would've liked a reference to the lack of monotonic time, though; either an acknowledgment that it's a problem (because it's now fairly widely known), or a mention that a new proposal to fix it [1] is in the works.
The conversion feature is in fact very convenient.
We often keep different types for what we get from the user (JSON) and what we write on the database (e.g: BSON). Having the ability to convert between them without having to re-type everything is useful for a lot of code out there.
Go is better for applied tasks. Currently there is no faster way to write or simpler language than Go to write a highly scalable internet server that can handle 100-1000k concurrent clients on the commodity hardware. I suspect this applies to some big data analysis tasks in bioinformatics, that can be parallelized.
As a bioinformatician, I can tell you: no. Hardly anywhere you have that concurrency need. You have a few clients only, typically, but with very highly parallel work-loads (as opposed to concurrent ones). Go is a bad for there.
This slideshow doesn't work on narrow browsers: a narrow browser window clips the text, despite there being more than enough window space to display all the information on the slide.
Remember when the Web was automatically adaptive? Remember when we preferred HTML to PDF because it adapted?
I've never used Go, but would you write your customer facing REST service using Go? Or would it only be used for back-end microservices? What's a recommended library for writing a customer facing REST API?
Well Apple stopped supporting 10.8, so why should Go continue to support it?
ARM6 support is a lot of work, actually, as IIUC a lot of stuff that the chip doesn't support needs to be done in software, and we don't have a reliable platform for testing against ARM6.
> Well Apple stopped supporting 10.8, so why should Go continue to support it?
I don't know, but Microsoft stopped supporting Windows XP many years ago, and it's still supported by Go. (Not that I care about Go on Darwin 10.8; just making an observation...)
Microsoft puts more effort into keeping things working than Apple does. Go works on XP as a result of the work Microsoft has done, not the Go project. Apple change subtle things in each OS X release making it onerous to support the older ones.
This is not true, Go "keeps working" on Windows because on Windows Go is ABI compliant and uses stable interfaces. In particular, on Windows Go interacts with the system through kernel32.dll and uses the standard Windows ABI.
Same is true for Solaris, where Go interacts with the system only through libc.so.1, and uses the System V ABI for the calling convention and thread-local storage.
On Linux the system call interface is stable (unlike Windows and Solaris), so on Linux Go "keeps working" too (albeit I will note that we don't use an ABI-compliant method for determining the current time...).
Darwin is just like Windows and Solaris, and unlike Linux. The system call interface is not stable, but unlike Windows and Solaris we use it anyway, and the method we use for thread-local storage is unportable and system-dependent. However, Darwin still has a stable interface through its own libc, and there's an ABI-compatible method to do thread-local storage as well. If Go would use the standard system interfaces on Darwin (like it does on Windows and Solaris), Go would just "keep working" on Darwin too and would not require changes each time a new macOS release is made.
It is true that Microsoft is very committed to forward and backwards compatibility, but only for its stable and documented interfaces (which Go uses), undocumented interfaces break all the time; Darwin's forward and backwards compatibility guarantees might not be as strong as Microsoft's over large periods of time, but they are still pretty good as long as you use the supported interfaces.
You can't test properly against emulators like QEMU. Emulators are written to be fast, not accurate (although in absolute terms they are pretty slow), e.g. they execute correct code quickly, but they don't fail to run incorrect code the same way real hardware would do. For example, when I wrote the arm64 Go port, I quickly discovered that the emulator would not cause a trap on unaligned memory access! Incorrect code executed just fine on the emulator. Even worse, I found several other bugs in a span of few days. In the end, I ended up writing my own arm64 emulator before hardware became available. I finished the port on real hardware.
Of course, in principle an emulator could do perfect emulation, but in practice testing Go on an emulator would mean testing and maintaining an emulator as well.
Apart from all that, running the Go test suite in a reasonable time requires a reasonable fast (e.g. server class) computer. Emulators just don't make the cut. And neither do small/old ARM systems.
We could reduce the scope of the tests for embedded platforms, but then somebody would have to step in and work on and maintain those platforms. People always complain when the minimum hardware requirements for ARM are increased, but never offer to step in and help... Personally, I am interested in Go on embedded systems, but I don't have the time to maintain this as well.
Coming from the silicon chip validation world, I mean the actual definition of "emulator," not the abused version of the word that actually means "simulator."
Sorry, I thought it would have been more obvious in this context -- it wasn't clear that by "even Linux still supports ARM6," I meant even the Linux OS kernel supports the architecture, not that QEMU for Linux supports it for running guest OSes.
Generally, compiler development is the intended use case of these emulators. I'm pretty unsympathetic when you say that; yeah, it's slow, it's an emulator, and using it is part of your job description.
I wasn't aware the Go team at large all had or needed hardware for all targets? I've done Linux kernel dev without a SPARC, Alpha, etc.
Google and first-class contributors to the ARM6 target (I'm sure a relatively small percentage of the Go community touches each individual, specific compiler target) should have no problem getting free or extremely-discounted licenses from ARM (and even test hardware) -- after all, it's in ARM's best interest to have lots of end users writing code that targets their platforms.
First of all, we do use emulators. Personally, as a Go compiler author I have written several emulators to develop (or debug) several Go ports, and I have used many emulators written by others, ranging from open source, to commercial, and even to secret emulators that have never left the hardware division department.
Yes, as a compiler writer I deal with how painfully slow these emulators are. Usually it's not a problem. When it's a problem, the payout is usually large enough so that modifying the tests is a good idea.
But all of this doesn't matter in general, we were discussing about the Go continuous integration builders. These tests run for every commit (and even before commit), for every change, from any contributor, and test everything. Emulators, even fast and inaccurate ones, and even most low-end hardware is simply too slow to allow for this.
Funny you mention ARM and "discounted licenses", because we've been under negotiations for several years to get something like that from them, and even though the arm64 Go port was commissioned by ARM, we still didn't get it yet. I've been promised we'd get what we need, but the bureaucracy and lawyers and approvals simply make any endeavour like this take literally years, and what we will get in the end is something that can be used by a select few, not by any potential Go contributor.
Yes, the Go project has access to all targets. It's all real hardware. It's a requirement for any new port. And every change is tested and must not break any target.
My advice is be demand rather than supply driven. Be driven by what paradigm and language is suited to a problem, rather than just what can I apply my new silver-bullet language to.
One of Go's other design decisions is signalling failures by returning errors. Multiple return values makes it possible to do that and also return a real value.
If you didn't have multiple return values, you would have to do something ugly: C-style pseudo-return via a passed-in pointer, or returning an error or a value as an interface{} and requiring the caller to type-switch on it. Or add a special case to the language to somehow allow an error return alongside a normal return. Multiple return makes this straightforward and uniform.
My guess is it comes from its C language roots, where every method returns an error code. With multiple return values, you can return an error code and the return value. This is a nice improvement over having to do my_func(in, &out).
Is go something you'd like to use? Are you happy with the stack you're currently using? What is that stack?
There are clearly people who are getting things done using go, and finding generics aren't something they require. Dumping on a language you don't like is boring and gratuitously negative.
I also hate any command that has more than, lets say 3 spaces, for its complexity, but hopefully this conversion stuff is more or less just a one time job so: who cares ;-)
Golang really seems to have come a long way. But what holds me back from using it are the dangers of deadlocks and segfaults (due to forgotten error handling) that might be introduced even inadvertedly if applied to industrial-scale projects (say, 1M+ LOC, 10+ developers). That is, I see many small (server/microservice) projects flourish with Golang, and it seems an excellent replacement for certain types of C projects, but I wonder how Go enthusiasts believe it could scale to compete with Java or C++, due to the way it does error handling, and deadlocking issues with channels.
It's even easier to mishandle errors and get deadlocks in C++. That is in addition to all sorts of other fun like buffer overruns. If the team is capable of not messing these things up in C++, then they are more than capable of not messing up in Go.
Modern C++14 provides quite good support on those fronts, and modern Java8 has lost most of its "code notoriety".
But that's just arguing back and forth. Here's the real argument: What popular OSS projects of noteworthy scale are being developed in Go? I know a few dozens in either Java or C++, and even a few fairly noticable Scala projects (Spark, Flink, Play, ...), but I yet have to see anything written in Go that can be called "industrial sized".
If you want examples of "industrial-sized" Go projects right now, you may have to look at case studies for proprietary cloud infrastructure, e.g. CloudFlare, Fastly, DigitalOcean, SoundCloud, and SendGrid. These companies obviously don't open up their product code, but they've been happy to share some information about their use of Go.
Yes, I've noticed for years that Go gets heavily used in web service-oriented startups with many concurrent users (plus, its easier to pick up than Erlang :-)).
But what I would really hope to see is Go being used for anything else than servers/services. I understand this is all the rage for certain companies, but none of that directly touches my own interests. Is Go only good for that niche, or will we see Go being adopted outside that "web services world"? E.g., for building old-school desktop apps, Go's concurrency features might be pretty cool - if its not too low-level for that?
I've recently started programming in Go and I am having a blast. Plus, I am making my systems faster and simpler with Go. I love concurrency in Go. I love the concept of Goroutines, the simple and intuitive use of Select. Channels still present a few mysteries here and there... But I'll get it at some point.
But the n#1 thing for me in Go is: It's written in Go. It's refreshing to drill into the language details, I feel like I have learned so much from seeing the Go source code (and having it readily available with a Ctrl+click in VS Code).
Maybe it's because I don't have the "depth" of some of the HN users, but Go feels great to me.