> Readability. I always found the Go code I encountered quite easy to read and understand, both our code and external code. Some of the C++ I encountered, in contrast, took hours to fully comprehend. Go also forced me to write readable code: the language makes it impossible to think something like “hey, the >8=3 operator in this obscure paper on ouroboromorphic sapphotriplets could save me 10 lines of code, I’d better include it. My coworkers won’t have trouble understanding it as the meaning is clearly expressed in the type signature: (PrimMonad W, PoshFunctor Y, ReichsLens S) => W Y S ((I -> W) -> Y) -> G -> Bool”.
Claiming that Go should excels in readability or ergonomics is pure, Koolaid fever-dream delusion.
Is it cleaner than C/C++? Sure. It's still a painfully verbose language full of boilerplate and with zero concern for expressivity or the suppression of detail [0].
Which isn't to say it's overall a bad language. It prioritizes other things over readability -- like speed, enforcing consistency, keeping its primitive set small.
Speed of compilation, not necessarily speed of compiled code. Missing generics: deadly. Passing around just interfaces? At times clearly not sufficient. Their idea of closures? Looks messy to me. Having a special syntax just for threading stuff? Totally beyond lame!
Golang is absolutely not a replacement for c or c++. It's a better replacement for the other languages out there requiring a VM to run anything. In short golang is better at cross platform than these other platforms and is IMHO good for writing good tooling. One of my colleagues said that golang now is sort of like java was in the old, old days. Making the same mistakes and needing necessary features added to become truly productive.
In my opinion ternary stuff is short handed eye candy and not a great reason to discount a language.
c++'s collections and <algorithm> fundamentally and utterly thrash anything golang claims to have, not to mention the whole stupidity around building garbage collection into a language that wants to be low level.
> In my opinion ternary stuff is short handed eye candy
Granted
> not a great reason to discount a language
The ternary quote exemplifies an attitude at the heart of the language designer's priorities. That is, the lack of ternary is, in fact, much more than a lack of ternary.
I don’t see how that is clearer than giving operations a name.
Convince me?
I mean, I could decompose a lot of things into their more primitive representations from named functions, but when scanning a code review, I don’t want to miss a bug because someone transposed a colon in a slice operation.
It’s elegant in a minimalist way that all these things can be implemented in terms of slice operations, but why force everyone to reimplement these whenever they need to do something common that in other languages you just use the stdlib for and forget about?
There are pros and cons to be sure, but mainly I was just pointing out that the parent to my post was a bit of a straw man.
Of course you can give these operations names if you like, it's all up to you. In the form given you can account for every operation. It is easy to understand where the allocations are and where O(n) operations. There are no hidden temporaries which are quite common in other grammers.
I do often create stacks, dequeues, heaps, and other collections inline as needed. But I find this to be a lot cleaner then some other languages. It has the advantage of brevity and clarity. I can say I like this a million times over c++ template semantics, though I too am not a fan of boilerplate, so I can understand some people's resistance to this.
var stack []T
push := func(x T) {
stack = append(stack, x)
}
pop := func() T {
x := stack[len(stack)-1]
stack = stack[:len(stack)-1]
return x
}
push(value)
// ...
value = pop()
In fairness, my biggest day to day pain point of using Go isn't the oft discussed lack of generics nor it's unpopular error returns. What bothers me the most when writing Go regularly is that I'm constantly having to reimplement basic functions for working with slices. The lack of a push or pop. Even selecting the last element of the slice via the following really becomes bothersome when you start dealing with multi-dimensional arrays:
slice[len(slice)-1]
The lack of a push and pop is a small inconvenience but it still disrupts my flow - not to mention adds unnecessary burden on testing to ensure I haven't cocked up something that should be elementary (and those kinds of errors are often a pain in the arse debug too).
The latter isn't so much a productivity problem - I just think it looks ugly as sin. Which is why I sometimes add a .Last() method to any slice types I define where I need to read the last item regularly.
Python supports slice[-1] for the last element... Pretty reasonable. Also slice[0:-1] etc.
Swift also has a lot of array slice sugar, like array.last, array.endIndex, array.removeLast ... Obviously there is a trade-off to adding a lot of sugar to a language, in terms of learning the language, but leaving too little sugar in the language just leads to developers / library designers implementing the sugar themselves which leads to a whole mess of inconsistent code.
> Python supports slice[-1] for the last element... Pretty reasonable.
Lots of languages offer something akin to that. If not `[-1]` then something more OO like `.last`. Even the language I wrote supports it. This is why I made the complaint about Go.
> Also slice[0:-1] etc.
In fairness, Go can do that. You just omit the value for where you want the last (or first) element of the slice or array. eg
b := []byte("Hello, World")
world := b[7:]
(this would work with strings too but I'm using a byte to make it clear we're working with slices)
edit: just for clarity I mean Go has the syntactic sugar for stating the start or end of a slice - rather than a negative number of elements from the end of the slice. My point being that there is already some syntactic sugar in specifying slices so it's a shame Go doesn't take that further.
In python slice[0:-1] drops the last element. To get the same effect in Go you need world := b[:len(b)-1]. The len() needs to be there (your example is a different case).
Marketing and hype are the only things it seems. I came to this conclusion after using golang at my current employer, and reading discussions by people online, as well as talking to them in person.
It just goes to show how golang is poorly designed as opposed to them just putting this stuff in a library, instead of polluting the global namespace with things like "copy" and "append".
Reducing lines of code is not a free exercise since you make up for it with the length of the line and there have been plenty of studies that have shown how longer lines in written text are harder to read then shorter lines.
That said, I'm not going to argue that developer will find shorter lines easier to read than longer lines but I certainly do. However it's also not as black and white as "shorter lines are always easier for me to read" either because there are some examples where it makes more sense to have it run on as one line. for example if you're calling a function who's return is only used as the input for another function. eg
fmt.Println(strings.TrimSpace(" some string "))
makes more sense (in my opinion) than
s := strings.TrimSpace(" some string ")
fmt.Println(s)
This is why the Go idiom says "what is more clear on two," rather than "use multiple lines even when it doesn't make sense."
> studies that have shown how longer lines in written text are harder to read then shorter lines.
As are studies showing that bugs are correlated with more lines of code.
final var a = if foo() { bar() } else { baz() }
is much more readable and strictly less error prone than
var a int
if foo() {
a = bar()
} else {
a = baz()
}
> fmt.Println(strings.TrimSpace(" some string "))
makes more sense (in my opinion) than
What makes more sense is
" some string ".TrimSpace()
as it allows for easier reading due to call chaining. Of course the golang standard lib decides something else just for the sake of being different, and without providing a proper reason.
> As are studies showing that bugs are correlated with more lines of code.
Sure but do those same studies look at code with the same character count (ie longer but fewer lines) or are they just subtracting characters via subtracting lines. The ones I've seen were the latter in that they basically just said "less code == fewer bugs" - which shouldn't be a surprise to anyone.
> [single line code] is much more readable and strictly less error prone than [multi-line code]
You know, had you said that 10 years ago I'd have completely agreed with you. But these days I've read so much Go code that I now find the multi-line equivalent more readable simply because that's what I'm more used to reading these days. But we're not really talking about significant margins in either case. I mean you'd expect any developer to parse either statements with ease.
I will say that I have always hated reading the ternary operator - which is the preferred way of doing single line if statements in some languages. I'd take the multi-line approach over the :? syntax any day. However from a strictly artistic perspective, the single line version with bracketed blocks is the nicest looking. So I can completely understand why people would prefer that method. Honestly, if gofmt let me, I almost certainly would write code that way too.
> What makes more sense is: " some string ".TrimSpace()
Your now arguing the benefits of OOP over other paradigms and while I agree that Go's implementation of OOP is half-arsed at best(!!!) I still have no intention of entering into that kind of ideological debate. Sorry.
> Sure but do those same studies look at code with the same character count (ie longer but fewer lines) or are they just subtracting characters via subtracting lines.
For most practical languages that are used day to day, this doesn't really matter. How often do you see Java or C# programs that have very long FP style lines?
As a matter of fact, I keep running into cases where golang code is both longer in terms of line length, and line count compared to code written in Java with map/filter/takeWhile/etc.
You can have a multi line approach and use if expressions, and get both readability (which is kind of subjective), and not needing to assign to the same variable in each branch. golang just chose to go with the most verbose and most error prone option.
var a = if foo() {
bar()
} else if baz() {
qux()
} else {
corge()
}
I totally agree Go has its warts but you talk as if this is a unique property to Go. If we are going to handpick our examples then I could easily cite instances where Go requires less boilerplate code than Java and C#. So ultimately it does balance out.
I agree it would be nice if Go was more expressive but I dont agree with your points about it being more error prone nor less readable. In your example there isnt any errors that you could do in Go that you couldn’t accidentally do in the subjectively better code aside forgetting to assign to the variable, which the Go compiler would catch that anyway.
Plus all the examples of readability in this discussion are really just a few small percentages either way. If a developer can’t competently read either example then they shouldn’t be allowed near your code anyway.
Having written a lot of Go and Java (admittedly very little C# though), I’ve definitely found myself far more productive in Go. Not just writing code, but compiling, testing and deploying said code too. And at the end of the day productivity matters more to me than creating works of art in my source code. Which is why I don’t mind some of Go’s uglier syntax.
I’m sure other people might argue that they’re more productive in $LANGUAGE and I’m sure they’re also right too. The funny thing about productivity is it’s a case by case thing. Sometimes Go makes sense, sometimes it’s Java or C# or Rust or even C. Sometimes it’s a JIT language like JavaScript or Python. And some times I just need to hack something together quickly in Perl. This is why I think it pays to be agnostic rather than spending weeks of your life coming up with “reasons” to dislike programming languages.
That's not what I'm seeing from code bases of different projects I've been working on at my current employer. It's almost fully the case that any code base for a medium sized project would end up being shorter in Java or C#, and we didn't even discuss things like annotations for validation and similar things.
> In your example there isnt any errors that you could do in Go that you couldn’t accidentally do in the subjectively better code
It wouldn't catch this
var a int
if foo() {
a = bar()
} else {
baz()
}
Or even assigning it to a different variable `b`.
> in this discussion are really just a few small percentages either way
They add up quite quickly in any sizeable project. It's not just one offs here and there, you end up with functions littered in the code base that distract from quickly getting to understand the code when debugging a bug or an outage.
I found compile times for golang (building the entire project + unit tests) to be about the same as Java, meaning all this hype about fast compile times in golang to be just that. Not to mention that exceptions are far superior when debugging issues.
I agree, depending on the situation some languages would do better than others depending on the task. The thing is, golang seems to be used just because it has Google as a name behind it, not for its technical merit (and the vast majority of critical infrastructure at Google almost surely is still C++ and Java). This shows up time and again, as people are not able to defend the technical choices behind it in any proper way, more like "the golang authors are smart and they decided to have it that way", which has already been shown several times that the golang authors are quite bad at defending their decisions, and they're not experienced at language design to begin with (C is a bad language by modern standards). Golang would probably be fine for some small tools here and there (even for that, Rust or AOT Java would be a consideration), for anything larger, a static JVM or .NET language is strictly superior.
True but you could forget to do that in your alternative example as well (albeit you'd get no instances of a assigned rather than sporadic instances - however the point of testing frameworks is they should catch that kind of human error regardless of the language or it's syntax)
> Or even assigning it to a different variable `b`.
Actually the compiler would catch that too.
> They add up quite quickly in any sizeable project. It's not just one offs here and there, you end up with functions littered in the code base that distract from quickly getting to understand the code when debugging a bug or an outage.
I guess it depends on what you're used to but I've always preferred code that abstracted away longer or more complex functions into smaller ones. I guess that's the FP habits in me transferring over to imperative languages. In any case, I've never had any issue debugging such code when under pressure during an outage.
> The thing is, golang seems to be used just because it has Google as a name behind it,
That's complete and utter BS. In fact I had already cited reasons I like Go. so please don't assume that because you don't like something then it's automatically a bad language that other people can't like either.
> This shows up time and again, as people are not able to defend the technical choices behind it in any proper way,
People have and they do though. The issue is that there is a hell of a lot of language elitism in the the different programming language cults so it doesn't matter what reasons we might give - you've already decided you don't like feature x and thus our reasons are wrong by default. You demonstrated just this kind of mentality when you argued that people use Go just because of Google in a reply to a post that lists why someone likes Go.
> which has already been shown several times that the golang authors are quite bad at defending their decisions, and they're not experienced at language design to begin with
The arrogance in that comment is overwhelming. I look forward to the day you create something worthy of recognition and the inevitable backlash on HN from kids who assume they're smarter then you are in every way. This isn't me putting Russ Cox et al on a pedestal - this is me pointing out that talk is cheap and most of the critics on HN are just average engineers at best.
> Golang would probably be fine for some small tools here and there (even for that, Rust or AOT Java would be a consideration), for anything larger, a static JVM or .NET language is strictly superior.
Clearly not everyone agrees with you there because a lot of successful important projects are now based on Go.
You need to learn that features you prioritise are not going to be the same as features others might prioritise - and that having different priorities doesn't make one party wrong and another right.
> True but you could forget to do that in your alternative example as well
Not really, unless I'm misunderstanding you.
var a = if foo() { bar() } else { }
will (depending on the language) either not compile, or the type of `a` will be inferred to a common type of `typeof(bar())` and `None` (perhaps some `Any` type). And this would almost surely cause a compile time issue the moment you use `a` as the type you expect. The other way is to simply write
final int a = if foo() { bar() } else { }
and that would immediately not compile.
> Actually the compiler would catch that too.
Not quite:
b := someFunc()
var a int
if foo() {
a = bar()
} else {
b = baz() // meant to assign to a
}
> In fact I had already cited reasons I like Go.
I was talking about why the language became somewhat popular, not about why some people may like it or not. Some of the golang authors already worked on a predecessor to it, but it never got anywhere, because they were't at Google at the time, so it didn't have the Google brand behind it.
> People have and they do though.
Like the "arguments" about how "null pointers are part of the computer" or similar nonsense about why they included nullable by default pointers? Or that compile checked enums are not really useful because you can just check them yourself, etc.
> this is me pointing out that talk is cheap and most of the critics on HN are just average engineers at best.
This is just diverting now. You don't have to be a brilliant PL person to see what's good and not in the area, after using different languages in production and finding out what features are useful, and which aren't, and seeing others struggling with issues already solved in different programming languages and environments, or people writing hacks to get around the limitations of the language, ending up with more complexity than if the language supported those features to begin with.
> Clearly not everyone agrees with you there because a lot of successful important projects are now based on Go.
There are large projects based in C and assembly as well. This is a non-argument. I think it was kubernetes that was notorious for using large amounts of auto generated code because golang doesn't have generics. Not to mention that if you want to do unit testing you end up with a large mess of auto generated code to do mocking, an issue that's solved in other languages a long time ago.
It's just that people repeat mistakes instead of learning from them, and easily follow fads and are prone to claims that are not strongly backed. golang is another manifestation of this.
You are misunderstand me. I'm saying you could type the following by mistake:
if foo() { bar() } else { baz() }
Which is the equivalent of the human error you were demonstrating in Go.
> Not quite: b = baz() // meant to assign to a
Actually yes. You'd get the following error:
b declared and not used
The go compiler checks for variables declared and, well as the error message literally says.
Go's compiler is actually very good. The error messages are descriptive and it's strict enough (though some say too strict) to catch a whole plethora of silly user errors.
Sure, other compilers have this too. But the only one I've used (at least recently) that betters Go is Rust.
But of course you should already know this because you're an expert in Go. ;)
> I was talking about why the language became somewhat popular, not about why some people may like it or not.
The two are mutually inclusive. The language is popular because people like it. Again I'm forced to reiterate the question: "Why do you find it so hard to accept that other people might like something you don't?"
> Like the "arguments" about how "null pointers are part of the computer" or similar nonsense about why they included nullable by default pointers? Or that compile checked enums are not really useful because you can just check them yourself, etc.
Clearly I'm not going to agree with every defensive point ever made about Go but just because you can cherry pick a few of the more absurd examples doesn't mean that the well reasoned ones aren't valid.
> This is just diverting now. You don't have to be a brilliant PL person to see what's good and not in the area, after using different languages in production and finding out what features are useful, and which aren't, and seeing others struggling with issues already solved in different programming languages and environments, or people writing hacks to get around the limitations of the language, ending up with more complexity than if the language supported those features to begin with.
That wasn't what I was commenting on. It was the comments about how people who are clearly more experienced than you seemingly know jack shit in your outspoken opinion.
You're just letting your arrogance get the better of you by making defamatory and clearly untrue comments about your own peers and developers with likely decades more experience in designing programming languages. I'm just pointing that out.
You don't have to agree with the design of Go but calling them incompetent and stupid is clearly taking things too far. In fact it completely undermines your own credibility.
> There are large projects based in C and assembly as well. This is a non-argument.
And C and assembly are well suited for some specific domains as well.
> This is a non-argument.
Your argument is that Go isn't suitable and I was evidencing how it is used in the very fields you assumed it couldn't. That - therefore - is the very definition of a valid counterargument.
> It's just that people repeat mistakes instead of learning from them, and easily follow fads and are prone to claims that are not strongly backed. golang is another manifestation of this.
"Mistakes" as defined by your own binary view of programming languages?
"fad" defines something as short lived and Go has long since surpassed that stage.
I don't know if your comments are driven by insecurity or over confidence but, honestly, your attitude here is pathetic. I never set out to try and convince you to use Go - just to try and help you understand why some people like to use it. But since this is clearly just an exercise for you to assert your own arrogance onto the entire Go community - I'm going to quit the debate.
> You are misunderstand me. I'm saying you could type the following by mistake:
if foo() { bar() } else { baz() }
Then there wouldn't be a variable assigned to use in the first place. This is not the issue at hand here.
> Actually yes. You'd get the following error:
b declared and not used
The first line I wrote declared and assigned to b, but in the if/else statement, b was overridden, so the error you mentioned won't happen, it will simply get overridden and a bug would happen.
> "Why do you find it so hard to accept that other people might like something you don't?"
It seems most people don't realize the other advances in languages designed to reduce errors, which golang discards on purpose and without good reason, and they just accept the hype and marketing around golang. You keep hearing that golang's gc is the best gc around and things to that extent, clearly incorrect nonsense.
> Your argument is that Go isn't suitable and I was evidencing how it is used in the very fields you assumed it couldn't.
The argument is that you can use any (badly) designed language to write large software, it will just end up costing more effort and resources (e.g. see javascript or large programs written in ruby and python, they're doable, but with a very large cost).
Using things better suited for the task at hand is important, especially seeing how software these days is not up to par. Then you have another badly designed language (golang) that decides on purpose to ignore research done to improve software reliability, it's not a surprise things the way they are.
> It was the comments about how people who are clearly more experienced than you seemingly know jack shit in your outspoken opinion.
Being more experienced doesn't mean not falling into a closed way of thinking, which clearly shows if you follow the golang authors and their history. This is an appeal to authority fallacy.
> And C and assembly are well suited for some specific domains as well.
That's not the point of discussion. The point is that for practically anything other than some small tool type work (even there it's arguable), there are other strictly superior offerings.
> to try and convince you to use Go
I already use it at work, that's how I'm aware of it's enormous shortcomings, by using it myself, and hearing and seeing how others use it and complain about it as well. That's why it's a fad, the company is quite invested in it now so it's difficult for them to switch, so they have to find hacks to deal with its shortcomings.
oh geez, this whole conversation is a depressing read.
@apta I've noticed every single comment you've posted on this topic has been a rant at Go. It really sounds like the issue is you rather than the programming language. If you hate your job that much then go work elsewhere. If you're the expert developer you claim to be then finding other work shouldn't be hard for you and the upside (aside better job satisfaction and potentially more money) is you then feel less compelled to shout at people on Internet forums.
I disagree strongly, at least as far as my intuition is concerned.
it's not code density that matters, it's "context density". Long drawn out functions are usually not hard to read because they are long, but because it's not clear what they are about. It's lack of conciseness on part of the programs logic that makes programmers lose focus, not code density.
As an example, think of a few fairly long switch statements or pattern matching logic. It's non-dense code depending on your language, but not hard to understand even if long. In contrast, some convoluted Haskell syntax with weird operators you've never seen is almost mentally incomprehensible.
On these terms it's true that Golang is not 'text dense' but it doesn't matter, it stops semantics from being overly complicated, and it encourages simple structures that don't go overboard on condensing information.
No cramming code into one line is never a good thing when you can make it clearer and easier to read by using 2, 3 or 4 lines of shorter more readable code.
Whatever the "proper" implementation of these slice primitives is, for me the real problem is that, due to the lack of generics, one can't write a utility library that provides simple names for these primitives.
Deleting from a slice is ugly and awkward because it's slow. Go, like C, confronts you with the real cost of what you want to achieve. A builtin like 'delete(a, i)' looks like an O(1) operation, when in reality it's O(n).
In what way does delete(a, i) look like an O(1) operation? It looks like a function call. You can never just look at a function call and see its complexity.
You make it sound like deleting an element being ugly is a design choice, but it can't be a choice since there is no alternative. Swap-and-pop is O(1), but it's ugly too.
I find Go hard to read because it is so monotonous (and a bit ugly) that I cannot concentrate.
For me, aesthetics matter, so my readability preference goes something like {Lisp,ML,Haskell} > C/C++ > Java > Python > Go.
C is actually quite high on the elegance level. C++ is only that high when written by people with self-restraint.
Rating Java above Python is not a mistake if you consider larger code bases. Also, Python suffers from some of the monotony problems, especially when there are many conditional statements.
I’m confident that a C++ translation of the new Go code would be less than half the LOC of the Go version and more type-safe, due to C++’s polymorphic functions and types. A Haskell rewrite would need even fewer LOC, and if I’d been allowed to write it in Clojure I suspect the whole thing could have been expressed in fewer than 1000 lines of macros
Indeed if you actually are using Haskell in production, there's no way your coworkers won't be able to understand a simple signature with three classes. They probably aren't Haskell beginners. Please, have some confidence in your coworkers' intelligence and reasoning ability.
That’s a good point, but often a type signature constrains the possible programs to such a degree that there is only one nonsensical program that can be written with that signature.
This sentence is gold J