Go is a language that pushes remembering corner cases and failure conditions onto the programmer rather than the language and runtime itself.
When you already have to remember a myriad of corner cases for business logic, also remembering so many corner cases for your code hurts productivity.
I also believe that languages exist to make getting to an end result in given domains easier. Go does not make my life easier.
I really hope it gets generics. I wish it would do away with nil/null.
Nim is a very good language that actually accomplishes the simplicity Go wanted imo.
Go affords simplicity to the Go compiler writers at the cost of burdening Go users with having to remember inane things.
I don't think that's possible to retrofit onto a language. Best you can do is to add non-nullable types. But zero values are so core to Go's semantics that I kind of doubt it's possible to even add those in a sensible way.
Can you elaborate on this? I write go for 3+ years and I have no idea what corner cases and failure conditions do you mean.
Writing to a closed channel panics, but writing to a nil channel blocks forever.
Appending to a nil slice works fine, but inserting into a nil map panics.
If you have a function that returns an error struct, and you wrap it with another function that returns the error interface, nil returns from the inner function will no longer test equal to nil.
Defining a method with a receiver type of Foo, rather than <star>Foo, means all modifications to the Foo get silently dropped. This can also happen to methods that correctly take a pointer receiver, if their caller incorrectly takes a value receiver.
Maps are not threadsafe/goroutine-safe.
Expression evaluation order is not defined, and varies between compilers. (https://github.com/golang/go/issues/15905)
https://gist.github.com/patio11/bc883d566778c323742432c203e6...
(You can see it here in the playground, but try it on your local machine if you don't believe me and/or think the playground has an inconsistent understanding of what time actually means: https://play.golang.org/p/ltdV9dI609 )
As someone who writes Go every day for work,
I can't agree that Go is simple.
You may be confusing "simple" with "good". A simple solution to a complex problem may not be a good one. Go can be simple and still not a great solution because it pushes complexity to a higher level.Does it have "cheap threads", like offered by Go?
Coincidentally, I just looked at Nim this evening, wrote some code and came away with the opposite impression. I'll copy-paste my sort-of-blogpost on this from [1]:
Nim itself feels a lot unlike Go and, interestingly, a lot like C++:
1. Non-orthogonal features. In C++, there are references, which are like pointers, but not quite, so you always have to think about which one to use. In Nim, non-orthogonal features include tuples vs. objects, and sequences vs. openarrays.
2. Feature creep. Just look at the language manual [2]: generic functions, type classes, 10 calling conventions (10!), garbage collection (not sure if optional or not), inline assembler, operator overloading, exceptions, an effect system, AST macros. Name any contemporary programming language feature, chances are that Nim has it.
Then there's the documentation. The language manual [2] is okay-ish, considering the size of the language. But when I dive into the library reference, the built-in module "system" [3] is so outlandishly huge and the documentation so badly formatted that it takes a lot of hunting to find what's in this module (and what isn't). Just look at all the duplicate entries in the navigation bar on the left. The system module should definitely have been split into multiple modules for the multiple concerns it covers, possibly with reexports in the actual "system" module to make sure they're all imported by default. Some parts should just be moved out of it, for example the whole file IO business belongs into "os" IMO.
Another thing that concerns me about the standard library is how many duplication is going on in there. There are at least 4 different XML parser AFAICS, and two regular expression libraries, both based on the same backend (pcre). This might be the same confusion that most languages suffer from in their pre-1.0 stabilization phase, but especially then, it's a strong argument not to use the language in production pre-1.0.
The thing that really killed it for me that I was able to produce SIGSEGV by accident, without the compiler warning me about it. I think I wrote something along the lines of:
type Config = tuple
someSetting: string
anotherSetting: string
proc readConfigFile(path: string): Config =
var file = open(path)
defer: file.close()
# TODO: implement the rest
var cfg: Config
return cfg
var cfg = readConfigFile("./example-config")
echo(cfg.someSetting) # this produces a SIGSEGV; probably because
# the memory backing `cfg` is not initialized
In 2016, I expect any new language to warn me about (or outright refuse to compile) code that might access uninitialized memory or do any other unsafe stuff, especially for a program that will run as root.[1] https://github.com/holocm/holo/issues/8#issuecomment-2412822... [2] http://nim-lang.org/docs/manual.html [3] http://nim-lang.org/docs/system.html
However, if I write
echo(cfg.someSetting[0])
it will segfault. This makes sense because it dereferences a null pointer (in Nim-speak, a nil value). I would guess that's what you experienced.Dereferencing a null pointer is not unsafe. The program cleanly exits. Compiling that via C is sketchy though, because the C compiler may treat provable null pointer dereferences as undefined behavior.
Is it as good at concurrent services as golang is?
Project success in the software industry is abysmal, and we still keep thinking we can spin up another language that will contribute to project success because it let's us express ourselves in new ways. Well, how's that working out so far?
The reason why golang appears to have such wide adoption in such a short period of time is that it really does seem to contribute to helping devs get their shit done. Massive amounts of working code are being written in golang, and that's good for the software industry as a whole.
Currently I run a massive project written in the standard issue kitchen sink corporate language (C#). It's got generics, functional extensions, all kinds of shit to make the most discriminating programmer happy. Well guess what, IMO C# for all it's features still doesn't serve the business of software dev as well as golang because it doesn't pull off what golang is brilliant at (easy to code for wide range of skill levels, easy to mentor, easy to test, easy to hire for). The result is difficulty finding productive devs, and a code base that is not up to my preferred quality standards.
This may be hard to swallow, but it might really be the case that you can get more quality work done with more devs if toolchain simplicity is emphasized over language features. If the evidence continues to bear this out for golang, then it's time for me to shed some language biases just so I can remain competitive.
My experience has often been that whatever feature is lacking in the language tends to be made up for by huge code bases that are impossible to navigate, or using frameworks that abuse whatever dynamic features you have in the language horribly with added complexity in tooling and debugging.
> easy to hire for
There are 100x as many experienced C# enterprise developers. And that is being conservative.
I think if you're proficient in one Java-like, you're single-digit weeks from being proficient in any of them, so if you're choosing your first, choose whichever one is easiest for you to go with. For a lot of Unix people coming to Java-like from Python or Ruby, that easiest choice is going to be Go: it's fully unixy but doesn't have the heavyweight runtime.
- user defined record types
- user defined sum types
- switch/case statement with support for sum types
- unified syntax for value and reference types
- closures with lexical scoping
- parallelism support
- multi-pass compilation
Given that many mainstream languages don't offer even what Algo68 had, I personally understand how a Go developer might thing that "nothing is new under the sun" since the 80's. After all, Go ignores all progress in programming languages for the last 40 years.I recommend watching "Growing a Language", a legendary presentation by Guy Steele: https://www.youtube.com/watch?v=_ahvzDzKdB0
I do love the attempts of Go developers to rationalize Go's choices. But in the end it will end up being a hated language, universally recognized as a net negative in the industry. But that won't stop the working programmer from doing the same mistake again and again.
I've seen this meme being spouted so much every time Go's mentioned it's ridiculous.
No, piling up feature upon feature is not progress otherwise we wouldn't be using anything but C++.
Go is a language you pick for the right situation. If it's not enough for what you're trying to do, go for a different one instead of trying to expand in the wrong direction leaving you with warts, like Java's done, C++'s done, Python, JavaScript etc... which you will have to end up avoiding in order to write performant and clear code, counting on luck not to have to deal with code that abuses those features to create anti-pattern upon anti-pattern.
>After all, Go ignores all progress in programming
languages for the last 40 years.
I've seen this meme being spouted so much every
time Go's mentioned it's ridiculous.
Is it a meme when it is true? To support this question, witness the statements of Rob Pike[0] below.---
Regarding the utility of supporting first-order functions[1]:
I wanted to see how hard it was to implement this sort
of thing in Go, with as nice an API as I could manage.
It wasn't hard.
Having written it a couple of years ago, I haven't had
occasion to use it once. Instead, I just use "for" loops.
You shouldn't use it either.
---Regarding progress in programming languages[2]:
One thing that is conspicuously absent is of course
a type hierarchy. Allow me to be rude about that for
a minute.
And[2]: Programmers who come to Go from C++ and Java miss
the idea of programming with types, particularly
inheritance and subclassing and all that. Perhaps
I'm a philistine about types but I've never found
that model particularly expressive.
---The part about "particularly inheritance and subclassing and all that" is ironically a meme spouted by Go's community so much it is, if you'll pardon my borrowing your description, ridiculous. For the curious, there are many community "Go-isms" explainable by the Pike talk[2].
Even a casual reading of the "list of significant simplifications in Go"[1] (35 in all) is enough to reasonably support the "ignoring all progress" position.
Of course, YMMV.
0 - https://en.wikipedia.org/wiki/Go_(programming_language)
1 - https://github.com/robpike/filter
2 - https://commandcenter.blogspot.com/2012/06/less-is-exponenti...
That's not unusual at all. Look what Fran Allen said about previous language from those guys - https://news.ycombinator.com/item?id=11578995
This article was written to make Go look bad and unoriginal, but it inadvertently proves that Go is Algol's legitimate successor exactly _because_ it has all these features _and_ a working implementation that is available for wide variety of architectures and operating systems.
For me however I just never felt happy writing Go code. I have a couple of open source projects with it, so I have put it through it's initial paces to see if we fit.
The language that did make me happy was Elixir. Everything about the language and the surrounding tooling is polished. You end up with significantly less lines of code that's easy to understand.
Here's just one example from me - both examples scrape some info from HTML:
Elixir: https://github.com/sergiotapia/magnetissimo/blob/master/lib/...
Go: https://github.com/sergiotapia/gophers/blob/master/scrape.go...
You tell me which one is nicer to look at and easier to understand.
However, the Go version is way easier to understand. Mind you, I have very little experience with Elixir. In the interest of being pragmatic, the easier code is to understand, the easier it will be to maintain, and we spend much more time maintaining code than writing it fresh.
It is a balancing act.
As an industry we don't "do" training on work time.
So how do you convince developers to work on learning and development during their own time?
One way is to make the language fun and interesting.
> I'm yet to meet a 20+year developer who is wowed by extensive/unique/complex features
20+ year devs don't like jumping onto the latest unproven technique/language. Don't mistake that for wanting few/limited features in a language.
20+year developers arent driving transitions to go. It is fairly new developers wanting to switch because it's cool, it's new, and it helps level the playing field by bringing experienced developers down a peg or two.
Elixir is way easier to understand than Go. If you will put one week into learning it, you'll be a lot further than you are with go.
I have a couple decades of professional experience, if you are building a serious system, you want Elixir. IF you are building a devops tool, where a single binary with no install process is what's important, you want go.
But given all the containerization and distributed programming people are doing these days using go for that kinda shows to me that most engineering is done by people who don't understand distributed systems.
That is very interesting claim, but there is something more than just tooling and number of lines of codes - a paradigm. Elixir is a functional [1] but Go is imperative [2] programming language. It changes a point in discussion quite a lot, especially when you say 'code is easy to understand'. Personally I prefer Elm over JavaScript/React, because it is 'easier and simplier', but I remember a situation in college when after C#-course we had introduced Prolog and F# and many of newbies found functional programming very difficult... But maybe it is matter of taste.
> Everything about the language and the surrounding tooling is polished.
I don't have strong Elixir experience, but playing with Phoenix framework made me really happy to see how many packages are well documented to create backend for web application. But is almost perfect, almost - because it is not Go.
Go is way more performant (Elixir have results comparable to Python or PHP[3]), has great virtual file system [4], auto generating docs (godoc), gofmt, gorename, golint, gocode (no matter which editor you use - VSCode, SublimeText, Vim you have great autocompletion) and a lot of other things (i.e. examples) which makes learning Go easy for newcomers (i.e. devs who are bored of PHP).
[1]: https://en.wikipedia.org/wiki/Functional_programming
[2]: https://en.wikipedia.org/wiki/Imperative_programming
[3]: https://www.techempower.com/benchmarks/#section=data-r12&hw=...
1. https://github.com/mroth/phoenix-showdown/blob/master/RESULT...
2. https://gist.github.com/omnibs/e5e72b31e6bd25caf39a
3. https://groups.google.com/d/msg/phoenix-talk/hljH55fsqqw/eFX...
For instance, without changing too much, you could implement scrapeProfile like this: https://play.golang.org/p/sP34n9acy7 I think that reads quite nicely, although I'm sure someone else can do even better.
If you modified dumpToCSV to take an interface instead of the concrete type, you wouldn't even have to prepare the user structure. You could pass in the vcard directly.
Also the elixir-lang Slack channel is just full of incredibly nice people. :P
From what I've found so far, Elixir gives a migration path for just about everything except heavy number crunching. Several people who came to Go from dynamic languages have seemed to echo this sentiment.
Go to me reads like an ELI5 programming language.
But concurrency in go is a terrible hack, it's just slightly better multi-threading with all the deadlocks and mutex and hassles that come with it. Channels and goroutines are not erlang processes.
That so many people think of go as a concurrent language shows how little people understand concurrent programming.
Every engineer who thinks they are decent needs to learn at least one good concurrent language (elixir or erlang would be my suggestions.)
And what in Go is not?
A whole page discussing the virtues of Go by insulting people.
Besides, while the language itself may be more verbose than it could be, the standard library is extremely pragmatic and terse. It's like the opposite of the standard C++ library. E.g. to see if a string starts with another string in C++:
std::mismatch(prefix.begin(), prefix.end(), toCheck.begin()).first == prefix.end()
In Go: strings.HasPrefix(toCheck, prefix)
The Go standard library is full of things that do exactly what you want them to, whereas in other languages you have to manually do it yourself.In distributed systems, go is fragile and dangerous -- because it will panic. IT has no supervision system, and it has the potential for deadlocks, in fact, unless you engineer around it, all coroutines and channels will produce deadlocks and can silently kill your program. When that happens you have no idea why things are broken-- nothings happening.
And this is a language without a decent debugger!
Do you know when it will panic? Do you know you can recover from panic if you for example want to communicate with other systems that this node is going offline?
> it has the potential for deadlocks
I could write that for most of languages that have mutexes. This is design problem, not language problem.
> When that happens you have no idea why things are broken-- nothings happening.
It's only true if you do not know how to use debugger and don't know how language features you use works.
I can't help but think the whole article is filled with bursts of dishonesty.
A language like C++, which let you use the proper data-structure in about two lines of code, is a lot easier when it comes to data-structures. While the Go programmer implements a multi-map, priority-queue or red-black tree, anyone else will have moved on to an actual topic of interest.
If you need a particular data-structure, surely having one ready in the toolbox is a net positive, not a negative.
You make a good point, too, that multiple-return being the only way to do errors is more ideal than the language saying "oh, we support that, but we also have exceptions, too!" At least in a language with Go's philosophy, you can expect other people's libraries and your own code to play by the same rules.
Go's error handling however is terrible, absolutely the worst and its tendency to panic is atrocious. Especially without supervision or restart capability. HEre's a spot where elixir has it right and is vastly superior.
I'd be happier if panic didn't exist, but it is extremely rare in real world programs and the std lib.
Not a fan of this sentence. Why try to make it sound like Maps are unusual or bad? Just as fundamental as the list to real programming.
It's interesting to me that this philosophy comes from the Go designers at Google, and that Google is also well known for keeping vast amounts of source code advancing in lock-step in a single repository. From reading the recent article on Google's source code repository structure, I believe that being able to reuse code (e.g. data structure implementations) without versioning headaches is one of the intended and actual benefits. It's of course not that surprising that two different areas (Go design and repository structure) might pull in two different directions, but these are two important high level issues so it does seem a little inconsistent to me.
That's such a weird statement. If anything, those are likely more OOP-related than FP-related, and he didn't really point out what's so bad about "more functional paradigms", besides the implication that it might be harder for new hires to pick up etc.
Anyways, I see that Go reduces the learning curve and simplifies lifecycle of huge projects, but at considerable costs about language features and expressiveness. I myself if working as a developer would rather not bear those costs just for the sake of the whole clogs of the organization running a bit more smoothly, and also so that myself would not just program day-in day-out en masse with everybody else out there in an overly simplified language that potentially puts me at more of a disadvantage in my career path. Maybe the leaders of huge companies would have other thoughts and there will definitely be developers who are happy to fill those roles, it's just not me.
Really? Nothing? Sure a language like Rust has drawn from many other concepts in other languages, but it has done so while actually bringing high level features to a language that has zero overhead costs. But yes, it's not simple like Go.
Did Go need to make all errors unchecked? There are no guide rails telling you that you forgot to check an error result. This is a runtime thing you need to discover. Is this actually simpler?
Go made the decision to allow for Null, even after nearly every other modern language and other older ones are trying to kick it to the curb; Swift, Rust, Scala, Kotlin, no nulls (the JVM ones have a compatability problem, as does swift with ObjC, but still). Is it simpler to delay discovery of Null data to runtime?
Go decided to not have generics, to keep the language easier to learn and more approachable. It's hard to argue with this one. Like lambdas, it can be a complicated concept to learn, but once you unlock this in you code, you write less code and accomplish more. So yes, it's simpler, but at too high a cost IMO.
To me the innovative feature of Go is the small runtime built into the binary making deployment dead simple and easy. This is a million times better than JVM, Ruby, Python, Perl, etc. This is a huge improvement over Java, and something every language should have an option for. Ironically this is also the least innovative feature, because this is how static binaries in C and C++ have worked for years.
I think this article is very well written, but I don't think it's fair to the innovation going on in other languages.
(Disclaimer: I used Go, discovered the three primary flaws as I listed above, and then searched for a better language. It would be fair to call me a hater, usually I try to avoid this, but in this case that's fine with me)
Plain parametric polymorphism is super easy to understand. Standard ML could be learnt in a week by someone who doesn't know how to program.
Admittedly, the interaction between parametric polymorphism and subtyping is tricky and subtle. And it seems most programmers have gotten used to taking subtyping for granted. But what if subtyping isn't always a good idea? Say, because it forces you to reason about variance (which humans always seem to do wrong!).
(inb4: Yes, Go has subtyping. When a struct conforms to a given interface, that's subtyping.)
Don't get me wrong, I love me some parametric polymorphism, but it's by no means a simple thing as far as I've seen. Especially if you care about the effeciency of things (you can fudge a lot more wih lots of indirection/allocation, like Java does).
Not having "implementation inheritance" between structs helps a lot, though I'm not sure if Go's anonymous fields might pose a problem.
Have you ever actually tried to teach someone who doesn't know how to program? It takes months, even when using a simple language like Python. Or even BASIC, which was designed specifically for beginners.
Standard ML is a good language (especially considering when it was developed, in the 1970s). Somehow a cult has grown up around it that prevents people from seeing that it isn't the solution to all problems, just another tool in the toolbox. Sad.
This may be considered cheating since it isn't baked into the language but there are tools to do this at build time, here's one: https://github.com/kisielk/errcheck
Poor old Tony Hoare (algol was mentioned earlier (rightly) as an exemplar of innovation) but Null in a safe memory managed context is a different beast to a true Null reference.
Null appears then as something between a known state and an not quite an exception, it carries different semantics from either, and whilst this could be seen as more complexity, I think the "I just don't know" case in practicality is useful, if harder to reason about.
Your point about the runtime is very true. Partly because of this - error checking is overrated! Yes I said it! We have go code that has been running in a reasonably high scale production environment for over two years and there are `if:...;err != nil` blocks that have never been touched in millions of calls per day, for 2 years. We have redundant services and trap panics in the rpc handlers, the nil becomes very clear and the rest of the system makes good progress. We save lines, save tests, and release a single binary fast. One example of where Go helps us deliver value faster, by being able to choose to ignore exceptions. Many people find this very uncomfortable. I say they are mistaking where the true project risks lie.
It's funny, every language I know gives you an option to basically ignore the error and just pray. I get what your saying, but if this is the type of code you want to produce, you can still do that in other languages that have strong types around Null and Errors.
In Rust for example:
my_possible_error.unwrap()
In places where you are explicitly making that choice. And to me that's the big difference. Is it explicit or implicit/unknown?Is rust the only good alternative here to golang if you one doesn't want to write c/c++ ?
So all the ML languages, Java, .NET, Pascal dialects, Modula-2, Modula-2, Oberon and its descendants, Ada, Crystal, Nim, D, Rust, Swift, Objective-C, ...
With the caveat that anyone who may be maintaining/using/enhancing your code will also need to be able to "unlock" this. Keeping the language simpler has benefits beyond the initial code development.
I'm curious, when was that being said? (Perl 5 was released in 1994, JavaScript 1.2 in 1997)
I am not sure what improvement you are talking about. Deploying Go apps requires recompiling for the target platform. On JVM, you only need to install the JVM. There are also tools to wrap JVM apps in executable files that will automatically download and install a suitable JVM.
I'm a longtime Java engineer, it's a great language, but I do think the compile once thing isn't as big an advantage anymore.
With the advent of the LLVM, it's easy to target specific machines. rustup, even makes it possible to build binaries for every target environment you have.
And let's be honest, how many people target more than Linux/x86_64 on the server side? Even if you target FreeBSD or Windows, my bet is that your still generally only targeting one platform.
Btw, Rust has a great std lib that is very portable across all major platforms. https://doc.rust-lang.org/book/getting-started.html
There would be paralysis of choice if when you install Go you were forced to choose from that list, but you aren't.
I thought go get wasn't a package manager /s
The entire build chain with Go is probably one of the most frustratingly limited build tools I've ever used, which is probably why nearly every Go developer I've met has switched to using one of the third party options.
The latest Go implementation (Go 1.7) has made Go a lot faster. I would argue that it closer the speed of executables generated with GCC (gcc/g++) than OpenJDK, the Oracle JVM, Mono or the .NET compiler for C#.
Go (the language) can be made just as fast as C (the language), for many cases. Go has the advantage of making it much easier to use multiple processors, though.
The only thing good about Go, is being an evolution path for C coders willing to embrace a GC and some type safety.
Swift 3 looks good, though. They've learned the right lessons.
(Frankly, I doubted that a little, until I realized Al-*-Go was not actually written in Go!)
Not to mention Go is focused on a different use case. Go is gunning for microservices (with it's concurrency chops) and CLI based tools (being a single compiled binary).. whereas Android apps are a totally different beast that stands little to gain from either of those. In fact shipping multiple binaries for different architectures is a bit of a detractor for Android considering it supports MIPS, ARM, and x86.
> until I realized Al-*-Go was not actually written in Go!
Again, AlphaGo was based off technology from DeepMind, a company Google acquired.
Please atleast do some quick wikipedia browsing before spewing FUD.
So? Apple introduced Swift after Obj-C to make developing iOS apps easier. What about GOOG? Couldn't they at least use Dart or Go (both of which they developed) for android app development after Java? BTW, last time I checked, they're still in for a lot to come from Oracle.
> Again, Al-*-Go was based off technology from ...
So let me get this straight. They bought a technology which was apparently written in C++/JS and rewrote it in another lang, but then again, they did not choose Go or Dart.
Seems like some one needs a wikipedia browsing...