16 ms·
While there is certainly something to be said for simplicity in a language, I think Go is too extreme in this regard. What it gains in simplicity it looses in e
by erokar 7y ago
While there is certainly something to be said for simplicity in a language, I think Go is too extreme in this regard. What it gains in simplicity it looses in expressiveness. This leads to more lines of code per feature, and bugs in software has been shown to be a function of LoCs [1,2,3].
One example of Go's lack of expressiveness is that loops are not abstracted away, e.g. you can't use higher level constructs like map and filter on collections. There are other languages that IMO strikes a better balance between simplicity and expressiveness, like Python and Elixir.
1. https://ieeexplore.ieee.org/document/1702967 https://ieeexplore.ieee.org/document/1702967
2. https://link.springer.com/chapter/10.1007/978-1-4471-3003-1_3 https://link.springer.com/chapter/10.1007/978-1-4471-3003-1_...
3. https://www.amazon.com/gp/product/0735619670/ https://www.amazon.com/gp/product/0735619670/ (Chapter "Developer Testing")
- vhakulinen 7y ago> What it gains in simplicity it looses in expressiveness. This leads to more lines of code per feature, and bugs in software has been shown to be a function of LoCs If the lack of expressiveness equals to greater amount of code and thus more bugs (in Go), does the same apply for languages that are more verbose (say, Java)? And if language is more expressive and less verbose (say, Python or Javascript maybe?), does it mean less bugs?
- fluffything 7y agoThe OPs claim that it has been shown that bugs are a function of LoCs is unsubstantiated at best. The number of bugs in a program correlates with the number of LoCs, but that's about it (correlation does not imply causation). The claim is also quite absurd, since, for example, you can pre-process any C or C++ program ever written into a single line of code, yet this operation doesn't reduce the number of bugs in these programs, therefore the amount of bugs is not "just" a function of the amount of LoC. Languages with better abstraction capabilities than Go (e.g. Rust or Python), might require programmers to type less, but the resulting lines of code are often dense. For example, I'm quite comfortable with Rust iterators and Python lists comprehensions, but it still takes me much longer to parse what code using these abstraction does, than code that just uses a simple for loop. It definitely feels great to cram a 10 LoC loop into a 1 LoC list comprehension in python, but reading that code 6 months later never felt that great, even for code that I've written myself. I just need to stop at those lines for much longer.
- coldtea 7y ago>The number of bugs in a program correlates with the number of LoCs, but that's about it (correlation does not imply causation). No, but it suggests it, and in this case, there's not many other options that could explain this than causation. >The claim is also quite absurd, since, for example, you can pre-process any C or C++ program ever written into a single line of code, yet this operation doesn't reduce the number of bugs in these programs, therefore the amount of bugs is not "just" a function of the amount of LoC That's an irrelevant strawman. When people speak of LoC they mean as to how many LoC are needed for various tasks based on the expressiveness of the language. Not whatever old LoC based on arbitrary adding needless lines (e.g. by preprocessing to inline function calls)...
- pcwalton 7y agoReally? For loops are a nightmare. Here's one from SPEC 2006: for (dd=d[k=0]; k<16; dd=d[++k]) { satd += (dd < 0 ? -dd : dd); } The problem with for loops is that they are too flexible, and so there's more opportunity for misuse. Iterator functions are less flexible, and therefore easier to read. And this excessive flexibility doesn't even make simple things simple. Try counting down from N to 0 inclusive using unsigned ints.
- tfha 7y agoLoops in go are much less flexible than loops in C, you'd never see code like that in go.
- erokar 7y agoIn general, yes. The more lines of code per feature, the more bugs per feature. Also, the guarantees you get from a typed language like Java does not seem to prevent bugs to a meaningful degree. Probably things like programming culture associated with a language is more important, like a strong preference for testing. This is an interesting study on programming languages' effect on software quality: https://web.cs.ucdavis.edu/~filkov/papers/lang_github.pdf https://web.cs.ucdavis.edu/~filkov/papers/lang_github.pdf
- fauigerzigerk 7y agoI wonder if everyone actually does initial testing and bug fixing after committing, because otherwise any effect of programming language choice might be gone before the code reaches the commit logs. I'm not sure it makes sense to consider code correctness separately from productivity. You can probably get code written in any language to roughly similar levels of correctness. But how much work does it take to get there? That's what I'm really interested in.
- imode 7y agoTo add, here's a nice article on implementing map from scratch: https://blog.burntsushi.net/type-parametric-functions-golang/ https://blog.burntsushi.net/type-parametric-functions-golang... It illustrates what you have to pay to get this kind of functionality for arbitrary slices. I wonder how this would change with generics.
- Un1corn 7y agoI'm not sure I would have called Python simple, it's a great language and it's not as complicated as something like C++ but it's not simple. For example when should I use NamedTuple and when should I use a dataclass? Should I be using a list comprehension or a map/filter/reduce? When should I split that list comprehension? I have seen (and made myself) terribly long lines with only list comprehension and it was hideous.
- erokar 7y agoWhen I said Python was simple I was talking about the concepts, functions and datatypes in the core of the language. I agree that if you include all the modules that come with Python it is a "big" language.
- Scarbutt 7y agoYou can write perfectly fine Python without any of the features you mentioned.
- makapuf 7y agoSure, but the more language that you may not use to write perfectly fine programs but have to know to know the whole language the more it seems superfluous. (See the whole drama over walrus operator). Python has accumulated a bit of rust also, old ways of doing things that were replaced with more modern ways, but that you should not use often. New languages or languages that don't evolve fast don't have them. python is becoming more and more complex (not tragically like c++) and v1.7 was indeed much simpler but it's still a nice language considering its age and scars.
- fernandotakai 7y ago> Should I be using a list comprehension or a map/filter/reduce? yes, use list comprehensions -- they are more readable. >When should I split that list comprehension? just use common sense. if you can read it and understand without thinking too much, that's good. it's readability beats short code 100% of the time.
- jerf 7y agoThe results on code lines being directly related to bugs is getting old. Programming languages and practices have changed substantially in the past couple of decades. I'd want to see more recent evidence. Besides, in practice I find lines of code in Go vs. Python are only maybe 20% different in many common cases, if you ignore the struct declarations which I have a hard time calling "code". (Being not a Turing complete language, that particular subset can't be considered vulnerable to the issues that Turing complete things can have.) I find myself very frequently wondering how many people complaining about all the lack of abstraction in Go have A: used it and B: used it to the point they're writing Go in Go. (Go just blows if you're trying to write Python in Go or something, or if you insist that you know better and must use map, filter, etc. rather than for loops. For all languages X, writing X in X is important, but Go is really graceless if you don't learn how.) Now, if you do get to B, it is still true that Go does not quite abstract as "well" as some other languages, but it does abstract well enough that you can start having reasonably conversations about whether those other abstraction tools are actually paying their way in a lot of larger, shared code bases. If we throw out a ton of language complexity, but only pay a relatively small price, are they really carrying their weight? The answer will vary from code base to code base, but I think it's not necessarily some sort of horrid, unthinkably idea that not every program must be assaulted with the most powerful, complicated toolkit regardless of the price incurred by the complication.
- coldtea 7y ago>The results on code lines being directly related to bugs is getting old. Programming languages and practices have changed substantially in the past couple of decades. The results in those "past decades" used all kinds of languages, some far more advanced and modern than Go is today (e.g. Lisp, Smalltalk, Ada).
- _ph_ 7y agoAs someone who programs both in Lisp and in Go (and I have used a little bit of Smalltalk), I have to comment your statement. In a sense, Lisp is the most advanced language ever designed, and still, it is ignored by most of the programming community :). Equally, I think, Smalltalk does object orientation better than most languages which followed it. Both languages are mostly dynamically typed, so comparisons to static typed languages need to take this into respect, they are different beasts. On the other side, I think Go has an interesting mix out of static and dynamic typed features, having interfaces for static contracts and interface{} as a fully dynamic type, which still offers full type safety at runtime. Go structs have also some interesting properties, if you look at them beyond being containers. Any type can have methods, and structs can embed other structs and thus "inhert" their methods in a sense. This is not full blown object orientation, but gets you surprisingly far.
- eternalban 7y agohttps://play.golang.org/p/dOYpmSK-Xor https://play.golang.org/p/dOYpmSK-Xor
- dantillberg 7y agoI ported a fairly complex (thousands of lines of code, in use in production) program from Python to Go. The Python version is around 1/3-1/2 the size of the Go version, but the clarity with which bugs are visible in the Go version is astonishing. There's a lot of code in Python version that "looks right" and even "does kind of the right thing a lot of the time." But the Go version lays bare corner and edge cases that were not obvious in the concise Python version. I agree that Go usage does suffer sometimes from lack of generics. I've sometimes used code generation in its place, and it works, but it's a poor solution. At the same time, the lack of generics has helped me avoid over-abstracting in other places, which is a common bane of mine whenever I work in more "expressive" languages.
- sagichmal 7y ago> One example of Go's lack of expressiveness is that loops are not abstracted away, e.g. you can't use higher level constructs like map and filter on collections. This is (or was) deliberate, with the rationale being that it makes O(n) blocks of code trivial to identify in review. Whether or not you buy that argument is a separate thing, of course.
- coldtea 7y ago>This is (or was) deliberate, with the rationale being that it makes O(n) blocks of code trivial to identify in review. Whereas, greping for .map(), .filter(), .reduce() wouldn't?
- azth 7y ago> This is (or was) deliberate, with the rationale being that it makes O(n) blocks of code trivial to identify in review. Like how for (int i = 0; i < strlen(str); i++) { ... } is O(n)?
- coldtea 7y agoLet's give them the benefit of the doubt, and consider that they meant that: for (int i = 0; i < strlen(str); i++) { ... } could be grepped and easily discerned from: for (int i = 0; i < str_length; i++) { ... } and generally, that every looping point could be easily identified. After all, if you call functions inside the body, all bets are off as to what complexity the loop means anyway...
- h_r 7y agoCan you explain why you think it makes O(n) blocks trivial to identify? How is such identification made easier by manually writing out a `for` loop applying a function foo to each element rather than writing `map foo myCollection`?
- tfha 7y agoThe way many people read code, it's much easier to overlook three characters than it is to overlook three lines with indentation.
- alfalfasprout 7y agoAnd yet introducing higher level functionality also leads to more difficult to detect bugs. I'm not sure the "lines of code:errors" correlation truly applies to all languages. That said, anecdotally I too have found it much easier to find errors visually in go programs due to its simplicity. I find the same is true of C vs. C++.