The State of Go
talks.golang.org
talks.golang.org
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.
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.
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.
Sorry. I know some people love it!
Spring might look bloat in the start, but it's powerful. At present there's no framework in golang which has so much power and freedom...
People comparing it to C++ and Rust miss the point.
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.
[1] https://talks.golang.org/2012/splash.article [2] https://golang.org/doc/faq
I totally agree that Go is fantastic for services and networked things.
[1] https://github.com/golang/sys/blob/master/unix/asm_linux_amd...
It might also be worth commenting on these[0] Stack Exchange answers, too.
[0] http://softwareengineering.stackexchange.com/q/151610/54726
"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."
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.
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.
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.
Are those then "systems programming languages" too?
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.
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 both https://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.
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...
It just happens that Go is a better replacement for python than c++ in the general case.
Having a GC doesn't forbid that, in very specific cases.
Mesa/Cedar, Modula-2+, Modula-3, Oberon, Oberon-2, Active Oberon, Component Pascal, System C#, Swift, D are all examples of such languages.
That's possible in go with unsafe.Pointer. Go's runtime, GC and memory allocator are written in Go and make use of this.
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.
I also wrote a tutorial for newcomers like me: http://github.com/thewhitetulip/web-dev-golang-anti-textbook...
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.
Sounds like someone's ready for Haskell.
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.
Look behind hype cycles and often you'll find $company marketing department.
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.
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".
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.
"for...range."
"How do I iterate over my own type?"
"The hard way."
"What interface can I implement to make for...range work?"
"You can't. Our types are important enough to support properly, yours aren't."
As a programmer I expect more than that, and I don't respect people who meekly agree that creating types is properly left to their betters.
It's not a criticism, it's literally how the Go language creators themselves describe it. See the Rob Pike quote at http://nomad.so/2015/03/why-gos-design-is-a-disservice-to-in...
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.
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.
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.
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.
You may reject it, but the fact remains that that was explicitly one of their design goals when creating Go.
> ... a single quotation cited on a blog post written by someone who (by his own admission) is very new to the language.
A quotation is a quotation; either Rob Pike said those words or he didn't. Who cited the quotation doesn't make a difference.
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.
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.
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.
I have a hard time finding any use case for Go.
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++)
Out of curiosity, what are the libraries in C++ that you miss in Rust, or would have to re-write?
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).
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.
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.
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.
This paired with vscode + click to see other peoples code is a great platform to get started with systems programming and tools development.
Can't thank the go developers enough.
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.
This is probably more due to the fact that you moved from a dynamically typed language to a statically typed one rather than this new language itself.
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.
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.
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.
Interesting!
I haven't used VS Code since the beta, but it can do that now? Wow. I should give it a try.
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.
I see people complain at times about it's performance but there is always someone there to rebut that it's fast at some things but not others.
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.
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.
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.
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.
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.
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.
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.
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.
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"
A tale of two cities is an easier book for an English speaker than Les Aventures de Tintin.
Map applies a function to each item in a collection.
As pseudo-code:
Collection.map(function)
And in the parents example we have:
[1,2,3].map(&:to_s)
The only Ruby specific part is &:.
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.
I'm unclear where algorithmic complexity is coming into this. Can you clarify what you're trying to imply?
Can you given an example where map might increase algorithmic complexity like that where the imperative version would not?
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.
You're right: map separates looping mechanics from computation. In Go, that's a bit too much obscurity.
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.
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.
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.
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.
My favorite intro to functional programming concepts for those used to imperative coding is Sott Sauyet's Functional Programming presentation: http://scott.sauyet.com/Javascript/Talk/FunctionalProgrammin...
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.
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.
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.
> 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)
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.
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.
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.
They can, but that doesn't necessarily mean they do.
For example, the usage of Elixir macros, which are the primary metaprogramming tool in Elixir, is discouraged in the docs:
http://elixir-lang.org/getting-started/meta/macros.html#fore...
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.
OK, I think I'll stop with the mataphors now :)
https://warisboring.com/stop-disrespecting-the-turboprop-c00...
Agreed, and I'd further argue:
1) most people driving Ferraris aren't skilled enough to drive them properly
2) most people driving Ferraris have no need to corner at 120 MPH
3) most people driving Ferraris are just trying to show off
4) most people driving Ferraris are more likely to hurt themselves and others than to save the day through the car's performance and handling
(To be clear: I think we're in agreement, but the metaphor is worth explaining in depth)
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.
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.
Go is the most fun language I've been using. On the contrary, I don't understand how some people can enjoy Java.
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.
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.
>>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.
I've seen enough languages to make comparisons.
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.
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.
Initial release 2005. i.e. Young.
How could a 12-year-old framework not be old enough for you?
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.
After that, you'll understand that Java is on the spectrum of "easy" programming languages.
The IDEs are very helpful by the way. You only need one SDK, which is a single download.
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.
An excellent example is the handling of this bug report(§):
https://github.com/golang/go/issues/12914
which resulted in this language-change proposal:
https://github.com/golang/proposal/blob/master/design/12914-...
And then these commits:
https://go-review.googlesource.com/#/c/36255/
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.)
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.
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.
But, I could easily see looking back in 2 years and realizing you were right.
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:
t1 = time.Now()
...
t2 = time.Now()
diff = t2.Sub(t1)
t1.Add(diff) != t2
Times are hard :| t1.Add(diff).Equal(t2)
would still hold, because Now gets monontonic time, Add and Sub maintain it, and Equal checks it. // time = [wall, mono], just ints for simplicity
t1 = time.Now() = [10, 10]
t2 = time.Now() = [19, 20] // wall clock lags slightly on second measure
diff = t2.Sub(t1) = (20 - 10) == 10 // Sub only operates on mono-time
t1.Add(diff) == [20, 20] // Add adds `diff` to both wall and mono
[20, 20] ==?== [19, 20]
I'd expect those to be different, since they represent different wall-clock times.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.
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!
Elegant? Hell, no. It's an ugly hack.
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.
Easy to say 'not fully thought out'. It took Java from version 1.2 to 1.8 to fix its date/time library.
It took Java from version 1.2 to 1.8 to fix
its date/time library.
That is incorrect[0]. When spreading FUD[1], expect assertions such as these to be fact checked by others.0 - http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22joda-time...
1 - https://en.wikipedia.org/wiki/Fear,_uncertainty_and_doubt
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. ;-)
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.
Code review is much the same.
And thats why Go will dominate the market that once was meant for Java.
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.
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).
Go just...works.
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?
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.
- 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.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.
- 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?
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.
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.
That's it. I think OP just assumed panics in Go are what exceptions are in other languages.
And there’s nothing like checked Panics so you’d know if one will happen or not.
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).
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:
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.
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.
Calling a number generator with a negative limit is also a programmer fault, so no reason to provide an error here.
X includes
the language authors (who are using this more and more in the stdlib as pointed out elsewhere)
the authors of any library you use ... but
transitively, so this includes the authors of any library you use indirectly as well
Hmmmm ... what was the problem with (unchecked, or python's) exceptions again ?
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.
This is like saying "I'm happy to avoid the cognitive load of having to specify how my code should behave in case of an error".
Sure, your code is simpler as a result. It's also more buggy.
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.
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.
Example:
https://golang.org/pkg/math/rand/
``` func (Rand) Int31n
func (r Rand) Int31n(n int32) int32 Int31n returns, as an int32, a non-negative pseudo-random number in [0,n). It panics if n <= 0. ```
Standard behavior would be returning an error, not panicking,
See this:
https://blog.golang.org/defer-panic-and-recover
``` 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.
So better spend that time contributing to other parts of the Go ecosystem, or another programming language project.
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.
There is no language to bind them all.
I don't know how maintainable 10-year old Ruby code is though, on the other hand.
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.
90% type safety (probably even more) is more than no type safety. It's not a holy grail that all programming must strive for.
[1] JS Typescript and flow: https://www.typescriptlang.org/, https://flowtype.org/
[2] Python with mypy: http://mypy-lang.org/
[3] PHP with Hack: http://hacklang.org/
This only shows that the sweet spot is probably not in the extremes, but somewhere in between the dynamic type system - paranoid type system spectrum.
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.)
GHC Haskell.
The C++ Actor Framework is awesome
Also, I assume the 'no type safety' statement is just hyperbole?
Even the stdlib uses interface{} everywhere now: https://tip.golang.org/pkg/sort/#Slice
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 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.
Most wrappers should at least provide an option to statically link the C; I know the OpenSSL ones do.
And yeah most wrappers provide a static linking option but there's not much consistency which is rather annoying.
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.
Now, say you're a Google exec, you know you're losing a ton of developer hours as people ramp up
Why wouldn't ramp-up time be a big company's most significant cost?
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.
Example of lack of purity?
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.
Can't wait for aliases though.
Sorting arrays of objects or small hashes, based on arbitrary properties/keys, is quite useful.
[*] 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?
Try the source, it's pretty readable.
https://github.com/golang/talks/blob/master/2017/state-of-go...
Using it is a choice.
I agree its ability to work on mobile is limited and that could use a CL (or a few) to improve.
* 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.
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?
https://youtu.be/f6kdp27TYZs?t=380
https://talks.golang.org/2012/concurrency.slide#16
And do they let us store our code snippets in actual testable (or at least buildable) source files?
> And do they let us store our code snippets in actual testable (or at least buildable) source files?
Not that I'm aware of, no. That's a pretty cool feature actually!
As you kindly said, Reveal.js may probably work for you as a frontend for your tool.
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.
It should maybe come bundled with mix, as some other tools, that way it'll be more approachable.
Also there's a wrapper for it, which helps in the process.[0]
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.
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)
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.
All of those features come from editor agnostic golang tools.
In Emacs too. I'd hardly say this is a unique selling point of Go.
"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").
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:
https://github.com/Microsoft/language-server-protocol
https://github.com/Microsoft/language-server-protocol/wiki/P...
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.
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/
Looking at that list, I see Go is actually doing pretty well these days. I retract my criticism.
That said, as the page shows, having full editor support these days is getting pretty common.
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.
Gogland will be better, but for now, Jetbrains Webstorm with the Go plugin is pretty good.
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.
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.
Remember when the Web was automatically adaptive? Remember when we preferred HTML to PDF because it adapted?
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.
I do remember that we used to test against emulators but they diverged significantly enough from the real hardware that we stopped using them.
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.
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.
EDIT: The official one from ARM was the one I was thinking of: https://en.wikipedia.org/wiki/ARMulator
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.
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.
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...)
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.
Originally I am a Python programmer. Any advice for people transitioning for Python? What are some of the advantages of Go?
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.
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.
Simply run the command below:
go tool fix -diff -force=context state-of-go/tools/gofix.go
How is typing 59 characters simple?All the other rules are same as the last 7 years, you know them through experience after using Go for a week. Way simpler than most other languages.
That go fix command can be typed once and update millions of lines of code. Pretty simple.
You also meant to say the go fix command does a lot (which is great), not that calling it is simple (which is not great).
And 32 characters is not much longer than, say: python manage.py makemigrations
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".
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?