18 ms·
Experience Report: 6 months of Go
- thisarticle 5y agoI feel like this is a much more fair and well written blog post than the other Go blog post from a few days ago.
- PrayagS 5y agoYou mean this one https://news.ycombinator.com/item?id=31205072 https://news.ycombinator.com/item?id=31205072?
- thisarticle 5y agoYes.
- nu11ptr 5y agoI hesitate to say I thought this was a good article because it was highly negative and I don't think it focused enough on the positives (of which I think there is some - for example, it has very nice and highly performant lightweight threads with full blocking semantics via goroutines). That said, I'm not really a fan of Go even though I wrote it for a few years and I think the article covered pretty well why I don't generally care to write it (even though I don't agree with everything they said). I think I would say overall that I like the idea of Go better than I like Go itself. I like the idea of a simple language, but not the choices they made. I like the idea of simple tooling, but don't find their tooling simple to use (ironically, Rust's tooling is much simpler to use IMO). By being less expressive, it actually makes it more confusing to use IMO (in the same way I find dynamic languages more confusing because without static types, I'm less sure about what args a function takes). By keeping null, not having sum types, etc., I don't trust the code I write. In the same way I don't trust any code I write in Python unless covered by a test, I don't get much confidence in Go's static typing due to their implementation choices. In summary, I don't think 'simple' is the right metric because it doesn't necessarily make writing code 'easy' or safe. For me, languages that are highly 'logical' and 'compose well' are much easier to use in practice. A language should try and find the simplest way to express X, not remove X as a concept IMO, or else code simply will not scale or compose once past a few thousand lines.
- slimsag 5y agoso.. Haskell and Scala? Those would be the top two that come to mind for me when someone says "highly 'logical' and 'compose well'", "having sum types", 'more expressive', etc. I've heard they're great languages (haven't used them much myself), but I probably wouldn't choose them for say an early-stage startup. Go's value is in being a mundane, repetitive, boring language. It makes it easy for any random kid to dive into an existing code base and become productive, that can be super valuable. There's a theoretical gradient of programming languages where one side is "has a single expression for exactly your problem, a single unique expression you've never heard of exists to solve every possible problem" and the other is "requires thousands of expressions to express your problem, but only a thousand are available" - or something like that. My point? There's no perfect language, yet people are always trying to find one. It's OK if you don't like Go and prefer another language, the real devil / tradeoff is in the fact that conformance to a single language (or set of languages) is such a strong social phenomena. I think that's why people end up so angry with viewed-as-subpar languages like Go gaining so much traction: it limits personal choice of which language to work in. I'm positive linguists aren't happy with English becoming the global language either, but you've gotta admit - having a global language is valuable.
- halfmatthalfcat 5y agoHaving written a lot of Scala, I generally agree until you can form a team that knows what they're doing or has a background in Scala. After that, Scala shines as the codebase(s) scale.
- ttfkam 5y agoSubstitute Scala for any other programming language and the statement still holds. Experienced developers and those with specific language expertise excel when implementing in that language. Who would have expected that? /s
- halfmatthalfcat 5y agoThe point is the barrier to entry for Scala is higher but once you have a skilled team working in Scala, you probably get more velocity than others due to the language ergonomics.
- TheBlight 5y agoI find that people with much more C/C++ experience (>5 years) tend to appreciate Go the most. Present company included.
- psyclobe 5y agoI think you meant to say 'C Experience'. No C++ coder I know (at least the true C++ coders, e.g. ones who have abandoned the 'Simplicity of C' mantra), find nothing of use in go besides a draconian single truth model of 'the best way to do things' similar to Python. That is really opposite of the C++ experience, where you have millions of different patterns, techniques, and pitfalls at every corner. Those who enjoy this, are definitely not go enthusiasts. Now I'm not saying ones better than the other, but I really doubt C++ core find Go attractive. Go was invented on the premise that 'We hate C++' or something to that regard.
- pphysch 5y agoC++ ICs won't find much to love about opinionated Go, but once they start leading/managing a team, they will like it a lot more.
- hamburglar 5y agoWell, good to know that after my decades of C++ experience, I’m still not a “true C++ coder.” You certainly can’t lose with an argument like that ;)
- dilyevsky 5y ago> That is really opposite of the C++ experience, where you have millions of different patterns, techniques, and pitfalls at every corner. Exactly right. And everyone who is serious about the mission and not “enjoying the process” is so so tired of c++ with its “millions of different patterns, techniques, and pitfalls at every corner” and c++ devs that need to be convinced not to do crazy shit just bc they can
- TheBlight 5y agoWhen I finished coding C++ professionally the general sentiment of the team was to use less C++ than more. When possible, it was advised to treat it more like C but with classes. The goal was stability above all else and easiness to reason about (for everyone.) That's why when Go was announced its design direction made perfect intuitive sense to me and anyone that spent years writing mission critical C++ on large teams.
- tgv 5y agoBit negative. I agree on some points (e.g. error checks on enums); other points, you simply have to learn to adapt to (initialization). The rest are (very) cosmetic preferences (overloading brackets; the compiler doesn't inform about typos). The biggest negative for me the author overlooked is the lack of non-nullable types. The positive thing the author doesn't mention is that it's easy to write in, nor that threading is really easy.
- rob74 5y agoWill "lack of non-nullable types" become the new "lack of generics" now they implemented generics? Guess we'll have to wait and see...
- tptacek 5y agoWhat are you trying to communicate here? That releasing one of the most popular languages in the industry without sum types is a form of original sin, and if they ever added enums and a match statement, you're be more right to hate the language? Some of the logic in these threads is just baffling to me.
- maleldil 5y agoMaybe? Generics were the most egregious absence, since it's challenging to express some constructs in a static language without them. Nullable types are another issue that other modern languages (e.g., C# and TypeScript) are trying to solve, but we it's a difficult issue to tackle when nil is already pervasive in the language. I think generics are a great addition to the language, and I'd love to see sum types (which would allow Option to circumvent nullable types), but I think that's much less likely.
- typesanitizer 5y ago> The biggest negative for me the author overlooked is the lack of non-nullable types. I did mention the pervasiveness of nil and the lack of sum types as negatives. > The positive thing the author doesn't mention is that it's easy to write in I didn't mention this because I think the "ease of writing" is superficial; thinking through edge cases is something that frequently consumes a lot more time than literally typing the code out. Also, given that the compiler doesn't really give any useful suggestions when your code is wrong (something that happens more often when you're less experienced in a language, like I was here), ease of writing takes a significant hit. > nor that threading is really easy. I didn't cover this because I haven't had the chance to work on much code using goroutines, and I've tried to ground the post in what I have actual experience with.
- synergy20 5y agoGo is my go-to language for cross-platform network application, the builtin https is enough alone, plus I can ship a true single binary in the field, can not be easier to upgrade. For other use cases, I use c/c++/python/typescript.
- blaisio 5y agoGo is my default language for any non-client-side project. That said, I agree with all the criticisms, except for the one about unused variables/imports and the lack of warnings in the compiler. I'd also add one of my own - I'm an expert go programmer, but I still panic sometimes when dealing with error handling. It is still not as easy as it could be to produce useful error return values.
- luxurytent 5y agoIndeed. panic is not overly recommended but there's a few places you can nudge it in that just make sense, rather than ensuring the error will successfully propagate up the chain.
- blaisio 5y agoHaha I meant panic as in become scared, not the go panic.
- luxurytent 5y agoHah, it works for both I guess :)
- luxurytent 5y agoThis is a good article. I am curious how the author compiled it. Everytime they came across a quirk they'd log it in a journal? Fun :) Figured I'd comment on at least one item which I ran into recently. > Sends and receives to a nil channel block forever. This did feel bizarre to me too, until I realized how well this works with select blocks. That IMO, is the primary justification for that design choice.
- tedunangst 5y ago> During this time, I’ve been making notes of speed bumps I’ve run into, as well as things I’ve liked about Go. This is a smart approach to a new language. Especially since you now have a list of things to recheck your early code for.
- rob74 5y ago...as long as you make an honest effort to understand why things you don't like are the way they are and don't just think "hey, cool, I found another thing to add to my list of things I don't like about Go!". Go is very opinionated and does some things differently from the mainstream. So you'll have to adapt your programming style in order to use Go successfully. Developers who aren't flexible enough will most likely hate it.
- o_1 5y agoGo is a tool. I haven't seen a language get as much directed criticism on HN in a long time. I appreciate genuine feedback, but only when its useful and direct. I can't remember a time when Java got ripped on HN this hard. Distancing oneself away from the religion of languages is the best thing I've done thus far. I "hope" the merits of language justify direction of software rather than the hype.
- sremani 5y agoDid you even read the article. Also, it was written by an individual and their experience with the language. The article merits a read or at least a skim. I cannot speak for others, but I do not see a cabal of people conspiring to bring down Golang on HN. Yes, esoteric languages get love and practical languages like C++/Go/Java et al. get hate because people are more familiar with them and see their warts. The more a language is criticized the more often it is used.
- abirch 5y agoDo we have an example of a language getting better with critism? I love the evolution of JavaScript but not sure if blogs shaped it.
- llanowarelves 5y agoSome people still call it a toy language because they are mentally like 15 years behind and think it's unreadable nested Jquery event emitter callbacks and Object.prototype overloading. The rest of us pushed for / picked up on the rapid improvements in tooling, spec, and best practices, causing "JavaScript fatigue", though that has slowed.
- daviddever23box 5y agoIt appears that many of the issues I see in articles of this type are often RTFM-level issues, especially when calling out linter exceptions (which a quick scan of the source code of an individual linter would help to explain).
- 5y ago
- alexchamberlain 5y ago> The loop iteration variable is reused across iterations, so capturing it by reference (the default for closures) is likely to lead to bugs. Is there a language where this isn't true?
- masklinn 5y ago> Is there a language where this isn't true? Java[0] and C#'s foreaches, Rust I think[1], Javascript's `for...of` when you use `let` or `const`. Probably a bunch of others, this is just off the top of my head (edit: just checked, Swift as well) And obviously languages which do away with "imperative" iteration entirely e.g. erlang, haskell, clojure, ... And it should be noted that this is more problematic in Go than in most, because of Goroutines (if you create goroutines using closures in a loop you're hitting this issue). Javascript was extremely hard hit by that (because of closure-based async stuff, and also that `var` is even worse) for similar reasons, which is what led to to `let` and `const` having so much better scoping. Incidentally, I assume that's at least one of the reasons why the order of evaluation of the `go` statement is so weird. And why you probably should not use anonymous functions to create goroutines. [0] also Java doesn't allow closing over variables which are not effectively final, so the issue couldn't happen, if foreach variables were not effectively final the compiler would reject the closure [1] though the borrow checker will usually tell you to get bent before you can even run the code
- kgeist 5y agoC# since version 5.0
- oxplot 5y ago> Errors on unused variables are annoying as well. > Not everything that should be done needs to be done right here right now. Hence the ability to suppress it with `_ = unused_var`! The point is that it's explicit. You have an out — it's not the pretty out you like but that's the whole point. It's unpretty and annoying in order to force you to think twice. Every design decision is Go has been the result of consensus of multiple people who've been bitten many times by the issue the design is addressing (in case that wasn't obvious). Have a read of issues, drafts and proposals on Go issue tracker to get a feel of what it takes to get something in. > Imagine trying to learn a musical instrument and being berated at every time you play the wrong note. That’s not a way to teach; it’s a way of asserting dominance. WTF! > No sum types with exhaustive pattern matching > I tried a search for a code pattern often seen due to the lack of exhaustive pattern-matching in Go > That’s 38.7k hits in the source code across GitHub etc. as of Apr 29 2022. Great. Write it up in an issue and with such an overwhelming evidence, it's a good candidate to make it to the language in the future. Why isn't it there to begin with? See above. > No overloading for common operations For many, that's a huge positive. When reading the code, it's much easier to reason about the extent of side effects for-loops have. > Yes, one can use map[T]struct{}, but that feels needlessly cumbersome. Now you're just trying too hard. > Go has a convention that doc comments must begin with the name of the entity they describe. Rob Pike, and docs, and blog posts talk about why this is the convention. Read up. > Limited markup support in godoc Thank goodness. You have a rust/swift programmer (from dozens of mentions of each language) trying to beat Go into a shape they're familiar with and not enjoying it. That's not the right way to learn and use a language, just as you don't go learning Japanese, expecting it follow the grammar rules of English. And especially in case of Go, bits are added pragmatically and after long and careful deliberation, not as a race to have as many features, bells and whistle as every other hot-lang out there. A experience report that keeps mentioned language X and Y as a benchmark for what language Z should be like, only tells how language Z differs, not whether it's better, worse, etc. So labeling the differences positive and negative is of little value in this case.
- Karrot_Kream 5y agoLook, it sucks when programming languages get condescendingly bashed flamily, but the OP did none of the sort here. I, personally, don't find things like the map-as-set syntax cumbersome, but I can see the argument from the OP. And OP also freely admits they have 6 months of experience with the language, enough to have the weird bits stick out, but not long enough to have internalized them. I don't think all of these are "trying to beat Go into a shape they're familiar with", I think they're legitimate complaints about the language. I don't find them problems myself, but I think it's good to document issues and pain points so that future language developments/languages try to incorporate this feedback.
- eikenberry 5y agoNo mention of CSP makes me think the author is still writing Go programs in a non-concurrent, imperative style. Used in this fashion you only get limited gains from Go's simple syntax and nice tooling. But writing using CSP patterns gets you a different experience and feel and is where Go really shines.
- halfmatthalfcat 5y agoGo's concurrency story isn't great compared to other languages tbh. Combining channels, wait groups and mutexes (because sometimes you do need to use all three or mix/match) leads to confusion on when exactly to use what, when.
- tptacek 5y agoIt's more or less the same as the story with Tokio programs in Rust; they just spell the word "channel" differently.
- Matthias247 5y agoYes. And if the metric is "confusion when to use what" then Rust (and especially async Rust) might fare even worse: Now there's multiple types of Mutexes, Semaphores, Channels: Awaitable ones and not awaitable ones. And one needs to understand how they fit into programs, and interact with all the other stuff. Most people which just pick an async Rust runtime because they read it's a great thing are having a rather hard time with this.
- kaba0 5y agoI just so don’t get the comparison of a high level language like Go to a goddamn system programming language like Rust. They are nowhere in the same league. Rust’s solution has to account for the true variability and complexity of the underlying platform, as otherwise it would be a bad low level language, while go can/could easily hide it behind a supposedly clever abstraction.
- evmar 5y agoAs a person who likes Go a lot, and who finds Go bashing -- and really, bashing in general -- pretty tiresome to read, I thought this was a pretty decent article and the sort of thing we ought to encourage on HN. At least in contrast to the usual rants. In particular I appreciated the author's interest in exploring the reasoning behind the design decisions they disagreed with, rather than stopping at "I don't like X".
- typesanitizer 5y agoThanks! I'm a fan of your work and posts on Ninja, so I'm glad to hear this. :)
- masklinn 5y ago> This seems even more strange; instead of giving a “missing type in composite literal” error, it gives a syntax error. That's a syntactic limitation (wilful I assume): `{1, 2}` is not a valid expression in general, however it is specifically allowed as an item within an existing composite literal: CompositeLit = LiteralType LiteralValue . LiteralType = StructType | ArrayType | "[" "..." "]" ElementType | SliceType | MapType | TypeName . LiteralValue = "{" [ ElementList [ "," ] ] "}" . ElementList = KeyedElement { "," KeyedElement } . KeyedElement = [ Key ":" ] Element . Element = Expression | LiteralValue . The "LiteralValue" item occurs only as a sub-item of the CompositeLit rule, which means it's not valid as a function parameter (or as a value to set on a variable, or as a return value).
- typesanitizer 5y agoIf you look at the GopherCon talk I gave (linked at the beginning of the post), it is about reading the spec. So yes, I did read the spec, and I realize that this is not syntactically valid (it would be a very basic compiler bug if this were valid syntax and it was diagnosed as a syntax error). However, the spec only states what _is_ but not _why_ it is that way. Sure, I could look at the git blame of the spec for every odd thing I run into, but there is only so much time in the day...
- masklinn 5y ago> However, the spec only states what _is_ but not _why_ it is that way. Sure, I could look at the git blame of the spec for every odd thing I run into, but there is only so much time in the day... Parsing simplicity and disambiguity (and thus speed) is a pretty obvious reason: if you allow `{}` to be an expression, then you have to look ahead any time you encounter an unprefixed `{` to try and figure out whether it's an expression or a block opening brace. Or you have to make your grammar into an unholy mess such that {} is an Expression but not an ExpressionStmt.
- honkycat 5y agoMy golang wishlist: 1. A error return syntax like =? In rust. 2. Sum types 3. Pattern matching There is a lot of boilerplate but I've found libraries like Uber/fx help a TON. Also I've been doing a lot of codegen using a library that can parse a package and return an ast API whose name escapes me right now... Overall I think the language is in a great place with generics added
- devmunchies 5y agosum types are my number one. the frustrating part is that it almost has it with type sets in interfaces, which you can use in function signatures, but you can't use them in definitions of other types. example, given an interface that is scoped to 4 types: type PlayingCardSuit interface { Diamond | Spade | Heart | Club } I can use that in a function signature: func PrintCardSuit(c PlayingCardSuit) { ... } But i can't use it to compose other types: type PlayingCard struct { Suit PlayingCardSuit // error Rank string }
- lelandbatey 5y ago> Cannot make a type in a foreign package implement an interface I would only push back on this point, and this point alone. Sure, it would be very convenient for me, an author to be able to just extend the implementation of anything that I import. However, when I am not an author and am instead a reader of code, doing this is the number-one way to causally make code totally unreadable. By allowing anyone to extend a type anywhere, it makes it impossible to just read the code. If the package that declares a type is the sole controller of that type, then reading code is easier. "Where is the definition of this method?" Answer: It's next to everything else for that type, in the package where that type is defined. However, if anyone can extend any other type, figuring out what methods even exist for a type becomes so difficult that you are forced to use a language-server (with all related dependencies installed) in order to use "go-to-definition". If someone wants to understand the code, requiring them to have a full-fledged IDE and/or development environment is pretty awful and quite onerous, and makes codebases tough to get into. For example, take this line[0] from a tutorial[1] on creating a simple snake game using the Bevvy engine in Rust. The main() function wires up loads of entities, including a `snake_eating()` function. But it also calls a mysterious `.after()` method of the snake_eating() function. If you do a ctrl-f on the file, you won't find an .after() method defined for the function snake_eating(). Just reading the code in that file, the only file in the program, you'll never find what the `.after()` method does or where it comes from. Only by opening that code in an IDE with go-to-definition will you learn that it's set via an automatic macro in the bevvy library[2] which causes all functions of certain signatures to implement the System trait. Which... is pretty tough to get into, and means just reading code without computer aid is effectively impossible. In your languages, please don't allow packages to extend the interfaces/traits/types of other packages. [0] - https://github.com/marcusbuffett/bevy_snake/blob/0.7/src/main.rs#L282 https://github.com/marcusbuffett/bevy_snake/blob/0.7/src/mai... [1] - https://mbuffett.com/posts/bevy-snake-tutorial/ https://mbuffett.com/posts/bevy-snake-tutorial/ [2] - https://github.com/bevyengine/bevy/discussions/1137 https://github.com/bevyengine/bevy/discussions/1137
- ngngngng 5y ago> doing this is the number-one way to causally make code totally unreadable. Absolutely, my immediate thought as well. I believe my experience reading and writing Go has been more pleasant than in other languages because people writing Go seem to shy away from hidden behavior, and I think rigidity like this helps. Also, to the author, "anyways" is not a word.
- Xeoncross 5y agoI really wish nil didn't exist in Go. It causes those familiar runtime panics like "cannot __ on nil" we love from those loose scripting languages like node.
- karmakaze 5y agoZero values are one of the tenets of Go. It's like saying I which Go had exceptions which is to say you'd prefer not-Go. Ironically Go was promoted as the anti-Java which we know is littered with NPEs.
- Xeoncross 5y agoI love zero values, I just wish Go was better at realizing I was using one.
- kgeist 5y agoNil values could be kind of tolerable if the language was always explicit about what is nillable and what is not. If you see something like "MyStruct" you can never be sure if it's an interface (can be nil) or a value (cannot be nil).
- tptacek 5y agoI understand the ambiguity you're talking about here, but how often does this actually bite you in practice? There are other context cues that you're dealing with a struct and not an interface, and the nil-ness of a return value isn't how you idiomatically communicate success or failure, even for things like map lookups where it would be somewhat natural in a C API to do that.
- deleted 5y ago[deleted]
- coolgoose 5y agoThey forgot to add that Go's date handling is a bit... different also :)
- typesanitizer 5y agoI didn't mention it because I didn't run into date handling code myself over the past 6 months. I've focused on the positives and negatives that I've run into in practice.
- truffdog 5y agoHonestly I kind of prefer it to the usual Unix date clone format.
- Andys 5y agoYeah, it took me so long the first time I came across it, I kept thinking I was missing something as it made no sense. But now that I understand it, it's fine.
- thegeekpirate 5y agoI had to write https://golangti.me https://golangti.me because I found it impossible to remember otherwise!
- imetatroll 5y agoNumbers 1 to 6.
- latenightcoding 5y agoGo is an ok laguage with a top-notch runtime
- omginternets 5y agoHa. This is quite true. I wish there were an (obvious) way to build languages on top of Go's runtime, in much the same way as Clojure/Scala/etc run on the JVM.
- Karrot_Kream 5y agoI think having the Go runtime be specific to Go is what makes it such an effective runtime.
- omginternets 5y agoWhy? And more to the point: binding an alternate syntax to the runtime wouldn't make it any less specific to Go.
- Karrot_Kream 5y agoA lot of Go's GC is tied up in the semantics of Go. An alternate syntax would indeed be an interesting idea.
- msie 5y agoI would be curious to know what he thought of Swift (having worked on the compiler). The language seems to be the opposite of Go in including every language feature under the sun.
- typesanitizer 5y ago> I would be curious to know what he thought of Swift (having worked on the compiler). The language seems to be the opposite of Go in including every language feature under the sun. Are you asking from a language design perspective? Or from an implementation perspective? From a language design perspective, yes, Swift has a lot of features. Most of these features exist for good reasons. - First-class Objective-C interop: Needed for initial adoption and migration, since Apple's SDKs were all Objective-C. (See also: Kotlin and Java etc.) - Protocols with associated types: Writing generic code with constraints makes surfacing type errors easier compared to templates. Associated types enable many natural patterns of programming. - Library evolution: Being able to evolve APIs without breaking ABI is super important for a platform. - Support for DSLs: Swift is used heavily for UI programming, and there is a convergence across languages in terms of having DSLs for making building UIs easier. - Use of weak pointers (vs having a tracing GC for cycles): Better for Objective-C compatibility. - Async/await + actors: Trying to balance usage of Dispatch (which is the platform API) with newer programming patterns, while still being able to compile in a way with low resource usage. - Upcoming C++ interop: Many big iOS applications use large amounts of C++, so better interop would make Swift usage easier for them. Does that mean I think every feature of Swift is perfect? No. For one thing, I think method overloading is way too flexible, which is what causes exponential time for type inference in a bunch of cases.
- BonoboIO 5y agoBit of offtopic: Best bash of a programming language „The Perl Jam: Exploiting a 20 Year-old Vulnerability“ https://youtu.be/noQcWra6sbU https://youtu.be/noQcWra6sbU And part 2 „The Perl Jam 2 The Camel Strikes Back“ https://youtube.com/watch?v=RPvORV2Amic https://youtube.com/watch?v=RPvORV2Amic
- zozbot234 5y agoTake note everyone, this is how you do well-argued criticism of a programming language or a technology more generally. Much more polite and better written than what we recently saw here at HN re: the same topic.
- WYepQ4dNnG 5y agoI wish an expressive language like Rust, but with a GC, so I don't have to think about borrow/checker and memory manager in general. I have tried to use Go but did not find appealing or ergonomic. I would choose Java/Kotlin over it, perhaps with GraalVM. If I had to write system tools, I'd probable go with Rust.
- zozbot234 5y ago> I wish an expressive language like Rust, but with a GC Ocaml or ReasonML are pretty close to that.
- pizza234 5y agoI've recently written a "system tool" in Rust, and, while it wasn't as bad, in terms of productivity, as I had imagined at first, there are certain domains where Rust is really a grind. Working with filenames/paths is one of those - if one works with (transforms) filenames/paths, the code will be polluted with all the conversions between PathBuf/Path/OsString/OsStr (and the canonical String/&str); this makes it hard to reason about the abstract logic. It absolutely makes sense that Rust forces one to consider the robustness of the code, but in some cases one just doesn't want such robustness. Cyclic graphs are another very ugly thing to work with in Rust (without supporting libraries).
- ______-_-______ 5y agoIf you don't care about robustness for paths with invalid utf-8, you could try camino https://crates.io/crates/camino https://crates.io/crates/camino
- tschellenbach 5y agoGo keeps it core feature set very minimal by design. The end result is a language that is almost as fast as C++ and almost as productive to write as Python. If you care about performance, but want to work with a small engineering team it doesn't get better. Sure you could use Rust to be a tiny bit faster in some use cases. But it's also less productive to work with for your team. You could use Python, it's a bit more productive but performance is 40x slower. The value of Go is the balance it strikes. That being said, yes a good enum type in the language, ideally like Kotlin's approach would be ideal.
- olah_1 5y ago> If you care about performance, but want to work with a small engineering team it doesn't get better. What about Zig? I guess people don’t like the lack of libraries there?
- deleted 5y ago[deleted]
- pclmulqdq 5y ago"Almost as fast as C++" claims about go tend to come from people who don't write a lot of C++. The perf gap is big, even though it's not as big as the perf gap with Javascript. That said, I don't think anything but Rust does any better than Go on getting the balance right.
- GlitchMr 5y ago> `filepath.Clean()` is not called `filepath.Canonicalize()` Canonicalization of a path is a different operation, as a name suggests it returns a canonical path to a resource. The idea being that if you happen to have two paths that refer to the same file (say, `/bin/sh` and `/usr/bin/sh`) then you should be able to pass those to path canonicalization function to get the same string for both. This is not what `filepath.Clean` does, so calling it `Canonicalize` would be confusing. For example, in Rust the following program when run in Rust playground (https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=4a7942a60ea5d9088a1e50faed82c7dd https://play.rust-lang.org/?version=stable&mode=debug&editio...) will output /usr/bin/dash: fn main() -> std::io::Result<()> { println!("{}", std::fs::canonicalize("/bin/sh")?.display()); Ok(()) } Meanwhile, Go's `Clean` function is only concerned about lexical processing and ignores the file system entirely and would return `/bin/sh` here, as none of rules `Clean` uses apply.
- typesanitizer 5y agoThis is a fair point. To be clear, I wasn't suggesting Canonicalize as _the_ name, but as one potential candidate. As you've shown, it has some shortcomings. Perhaps Normalize is a better alternative (and also another candidate that I suggest), since "Normalization" is a commonly used term for converting to a standard/normal form.
- aledalgrande 5y agoMy experience with Go is that it is pretty low level compared to languages like Ruby, but higher level than something like C++. I'd be curious to hear what people build with it at work, is it mostly microservices or are there also monoliths around? Is it more APIs or background workers? What do you think it's an interesting project I could build in my time that shows me where Go shines?
- kitd 5y agoCannot make a type in a foreign package implement an interface The idiomatic way of adding an interface to a foreign type is to declare your own local alias and use that to implement the interface. At least then the added functionality is confined to a known package and won't lead to surprising behaviour elsewhere.
- barsonme 5y agoLike every language, there are plenty of 'problems' with Go. But many of these seem like off-the-cuff complaints instead of thought-out criticisms. To choose an arbitrary example: nil is sometimes equivalent to an empty collection but sometimes causes a runtime crash. var a []int // initialized to nil _ = append(a, 1) // OK var m map[int]int // initialized to nil m[0] = 0 // panic: nil dereference It’s not super clear to me whether there is some systematic rule governing when nil causes a crash when using a built-in operation. Are crashes specific to write contexts and non-crashes specific to read-only contexts? I don’t know. The author is comparing two different operations. The fact that they're operating on nil variables is irrelevant. The equivalent slice operation is not the builtin function "append", but rather assignment: a[0] = 1. This will panic in the same manner as m[0] = 0 (albeit with a different panic message) A map-based operation that's equivalent to "append" would be a (hypothetical) builtin function like "func assign(m map[K]V, key K, value V) map[K]V". The language could define define that map assignments auto-vivicate the map when necessary. But that would cause each map to incur an additional allocation, even if it's never assigned to. And then for consistency you'd need to apply the same thing to slices.
- deschutes 5y agoWhy require types have a meaningful zero value? It's not necessary for value semantics. You can require that values be initialized and the machinery for that doesn't seem that bad. Zero values seem as arbitrary as requiring all types be equatable.
- barsonme 5y agoI'm really not sure what your comment means, sorry.
- deschutes 5y agoSo, my understanding is that: 1. Unless otherwise initialized, types have a zero value in go. For pointer types that zero value is nil. 2. It's encouraged for this to be meaningful. That's opposed to say java, python, or C++ where invoking a method on a null object is a runtime error (or undefined behavior). So for example, appending to a 'nil' slice is the rough equivalent of trying to add to a null List in java. I don't see how the go approach makes anything simpler. Value semantics are simply that the value of an object is all that matters. For example, two int objects '5' are the same from a value-semantic perspective. I guess this implies all objects have some value. This requirement can be satisfied by requiring they be explicitly initialized. Equatability is a requirement of objects in java. Not all types of objects are equatable beyond their identity (some unique identifier) though. For example, how do you equate two functions? To me this parallels the decision in go to make zero values a thing beyond a runtime error.
- matthewfcarlson 5y agoMan 10 seconds for a build and it’s already running? It’s like a 10-14 minute build on a high end i9 for me and then 2-4 minutes to flash the new binary on the hardware. It is hard for me to believe that a 30 second to 10 second build time speed up would be noticeable in a day to day workflow. But maybe I’m just envious.
- mwcampbell 5y ago> Go has a convention that doc comments must begin with the name of the entity they describe. Does anyone know the rationale for this one? My only guess is that the other common style, where the doc comment starts with a verb, allows for variation in how that opening verb is conjugated, e.g. "Decompress the tarball" versus "Decompresses the tarball". Maybe the Go team figured they'd eliminate that ambiguity by establishing a convention that the doc comment always starts with a complete sentence with an explicit subject.
- tptacek 5y agoIt's a weird call-out in the post, especially since their example is a non-exported function.
- typesanitizer 5y agoAh, making it non-exported was an unintentional mistake. I've pushed a fix marking it as exported with an EDIT note.
- tptacek 5y agoFor the substantive critique: it's also a bit weird because it's pretty clear what the reason for it is: it's a simplifying convention, like the capital-letters-to-export thing (which I'm partial to, since it's a convention I use in my C code). It seems reasonable to have preferences in the other direction, but (and I'm not trying to argue that you wrote it this way) not to suggest that it's somehow a flaw in the language.
- endorphine 5y agoI think they refer to the following suggestion: > Doc comments work best as complete sentences, which allow a wide variety of automated presentations. The first sentence should be a one-sentence summary that starts with the name being declared. [...] If every doc comment begins with the name of the item it describes, you can use the doc subcommand of the go tool and run the output through grep. Imagine you couldn't remember the name "Compile" but were looking for the parsing function for regular expressions, so you ran the command [...] source: https://go.dev/doc/effective_go#commentary https://go.dev/doc/effective_go#commentary
- benreesman 5y ago
- cannabis_sam 5y agoOh my God, as an average moron who decided to pin his professional growth in my current company on learning Go and Rust, these threads are paying dividends that I could not have imagined in my wildest dreams!
- AtNightWeCode 5y agoAt this level I was more annoyed about what goes into the libs and not. Very flawed. Scoping was mentioned with defer but it can be confusing in other cases too. I think if the progression of GO had been the same as we have seen with Javascript, C# or even Java. Then GO would have been a relevant general-purpose language today instead of this safe C alternative in niche areas.
- shintakezou 5y agoI "love" computer language criticisms, even though I don't believe neither that the perfect language can exist nor that a language can fit all the needs. Anyhow, here I didn't get what's wrong with some of the "issue". For example: you can't get the address of a literal, but you can take the address of a variable. This isn't surprising. And about arrays/slices/maps, append and make: it seems to me fairly logical if you don't disregard what they are. (If I've got the issue, and I am not sure about the exact point.)
- nathants 5y agowhat sold me on go: - go build. what keeps me on go: - gopls + errcheck + ineffassign.
- everybodyknows 5y ago> It’s not clear if a value that is passed via pointer is intended to be mutated or not. (const-ness / mutability) (maybe it’s passed via pointer just because the size of the struct is large?) The dilemma is even richer than that -- what if the function call is inlined, with the struct known to be instantiated in the caller? If so, size of the struct doesn't matter. In C, inlining can be forced, so passing a struct by value can be assured to be economical. The programmer has no such option in Go.
- omginternets 5y ago>The loop iteration variable is reused across iterations, so capturing it by reference (the default for closures) is likely to lead to bugs. >defer inside a block executes not at the end of the block, but at the end of the enclosing function. >defer evaluates sub-expressions eagerly. Whenever I see this kind of complaint, I can't shake the feeling that the author struggles to distinguish between "bad design" and "learning how things work". There are many fair criticisms to levy against Go, but "it didn't behave as I first expected" is hardly one of them. If it were, there would be lots more to complain about in the languages that are routinely touted as superior to Go, namely: Rust and Haskell.
- boolemancer 5y agoI disagree. Counterintuitive design is bad design, and leads to subtle bugs getting introduced. This is especially damning in a language where so many decisions are justified by a desire for simplicity and ease of understanding. You throw that all out the window when you make design decisions that are opposite to most people's expectation.
- Andys 5y agoI get what you're saying, but taken to an extreme, every language would be the same (or, we'd only have one language). After you get used to a subjective alternative it becomes the new normal.
- t43562 5y agoYes, very negative. I can't stand how miserable it can be to fork a library and in general to ensure I'm importing the correct version of the thing I need to import when it's not in github. There are other compensations - faster than python but still has decent regexps. Good crypto libraries. Channels (make life easy) and massively scalable goroutines. ...trivial cross compilation ... and many other things. I still find python much easier but, for example, I have very little reason to bother with C++ or Java now.
- ThinkBeat 5y agoThis is meta but in most fields 6 months of experience is not considered significant. "Things move so fast" Not really. We are doing mostly the same as always on the front end. Put dots on screen at the rigt time,right shape, colors etc. With over 50 years going at it, you would think this was a trivial effort that was well understood and solved decades ago. < Esp, after hardware converged to the rather uninspiring selection left. (This might actually get better now with manny companies getting in on desiging CPUs GPUs and so on I have some hope for a return to competition on those fronts )
- ufmace 5y agoI share at least some of the author's criticisms of Go. But it neglects to mention a few of my favorite things - the massive and mostly capable stdlib and the easy cross-compiles. How many compiled languages can you be on any of Mac, Windows, or Linux, and compile a binary for all 3 instantly with just a env var that always works no matter how complex your code or how many libraries you're pulling in? I can't think of any offhand. I like Rust better as a language for a number of reasons, but it unfortunately falls down on both of those. There's also a noticeable difference in how they're used based on the number and maturity of packages available for various things. Most of the Rust world seems to be more focused on low-level stuff. You can do stuff like web services and query web APIs and talk to databases, but there's likely to be only 1 or 2 crates for it, and they're probably maintained by a single person who (like most normal people) sometimes just stops doing anything for months or years. Golang is really made for the web services world, and it shows in the packages available - it seems a lot more likely there will be many top-quality and well-maintained packages for doing any web service like thing you might want to do.
- kaba0 5y ago> How many compiled languages can you be on any of Mac, Windows, or Linux, and compile a binary for all 3 instantly A little tongue in cheek answer, but Java and it does so in a single go as well :D
- warent 5y agoIn the recent Go critiques posted in HN I got really annoyed because the articles came across as snide and such-and-such miscellaneous things (that I expressed in a somewhat poor, reactionary way last time) In my humble opinion this article is very well written. While it leans more negatively and is a critique, you're being very professional and respectful. I appreciate your write-up and perspective. Some of these issues flow into problems I've also had with Go, particularly in trying to use it for a GraphQL API (which was a horrible idea!). Feeling cautiously optimistic about generics :)
- cpeterso 5y agoPeople address some of these issues piecemeal with linters and code generators, but maybe there’s an opportunity for someone to create a Go++ language that accepts Go syntax but also extends it with sum types, nullability annotations, no default values, checked error handling, operator overloading for collection, etc. I remember people were excited (and dubious) of the Go-like language V.
- stevenhuang 5y agoThe distinction at the end with the "New Jersey" and "MIT" approach was enlightening, as well as the empathetic remark on Swift's approach to keeping complexity within the language implementation vs foisting it on users.
- sidlls 5y ago"Changing pervasively used structures in C++ or Rust can cause recompilation that takes over a minute. That is enough time to get distracted by something else, like Slack." That is...absurd, to be blunt, unless one has a medical condition (e.g. ADHD). It takes a neurotypical person almost no effort to remain attentive to the task started during a pause in activity of a few minutes. If a person without such a condition is getting distracted in a few minutes' compile cycle, it's a flaw of theirs that they need to work on. Of all the things to point out about other languages, "over a minute" compile times is not a good one. Now, tens of minutes to upwards of an hour (some C++ code bases I've had the pleasure of working in) or more? That's an issue.
- cutler 5y agoMy experience with cgo has been less than stellar. I built a simple Fiber API with 2 Golang libs (gosweph and swephgo) which interface with the Swiss Ephemeris C library. Both libraries segfaulted when the API was loaded with more than a couple of concurrent connections via wrk or k6. I'm no C expert but the errors pointed to cgo as the culprit.
- riwsky 5y agoHad the same thought, reading the strings package. Why’d they mention letters? Were Ken Thompson and Rob Pike even aware of the concept of Unicode code points?
- hu3 5y agoSorry if I missed the possible sarcasm but Ken Thompson invented UTF-8 while working with Rob Pike. "UTF-8 was designed (by Ken Thompson), in front of my eyes, on a placemat in a New Jersey diner one night in September or so 1992." - Rob Pike source: http://doc.cat-v.org/bell_labs/utf-8_history http://doc.cat-v.org/bell_labs/utf-8_history
- umvi 5y agogofmt is a huge positive for me as well. Not having to think about formatting frees up more cognitive load than you would think
- levischoen 5y agoI love using golang AND agree with most things in this article being valid and fair points. Honest critiques can lead to healthy growth.
- blindseer 5y agoThat was a great article and put into words a lot of the feelings I have had about my experiences with Go better than I could have. I also learnt a few new ways to shoot myself in the foot :) The MIT vs New Jersey style of thinking was eye opening. And I also feel like my "values" lie closer to a language that prioritizes correctness over simplicity. I understand that means more work for the maintainers of the language though. I wish I had that framework of thinking a few years ago. Rust's emphasis on correctness and requirement that the user deal with correctness too (with sum types + exhaustive matches etc) is I think the main reason I enjoy the language so much.
- srer 5y agoI'm going to mention my own tiny experience report as a frequent SQL user, of Go's simplicity pushing a lot of burden onto the user in the relatively simple task of querying a list of things from a SQL table: http://go-database-sql.org/retrieving.html http://go-database-sql.org/retrieving.html - lets pretend we return errors rather than dying with log.Fatals :) There's a specific order of operations to be done here, and even a slight deviance could be a significant bug. To start of with we: 1. Do query 2. Check err 3. Defer close 1 is straight forward. 2 you can forget, then something bad may happen. 3 you can forget, which will cause a resource leak. If you switch the ordering of 2 and 3 something bad may happen. Instead of defer close(), a user might opt to just close() at the end of the function, but there's a reasonable chance they'll overlook the unhappy paths. Next we have iterating over the results: 1. For rows.next() 2. Scan into a &var 3. Check for scanning errors 4. Exit for loop, check rows.Err 1 is hard to mess up. 2 has some potential to mess up if you're not clear on which bit of memory you're storing the result in. 3 you can forget, which could cause you to get the previously scanned var show up multiple times, or zero values. 4. you can forget, which will cause your results set to (I guess?) be incomplete. There's a lot of different permutations in this code that will compile, and I think has a good chance of passing the average paid dev's test suite (it's a bit of work to exhaustively test the unhappy paths). In my experience people are especially prone to messing up closing rows. I don't blame em, we know from decades of C that manually freeing resources, especially in the case of errors, is tricky. If I've made any mistakes, please point them out, as it supports my stance ;) (There's more fun to be had in SQL with Go, like that SQL has optional types, but Go doesn't, which leads us to sql.NullString et al).
- bigwhite 5y agoI wish people would read this paper before criticizing golang - https://cacm.acm.org//magazines/2022/5/260357-the-go-programming-language-and-environment/fulltext https://cacm.acm.org//magazines/2022/5/260357-the-go-program...
- morelisp 5y agoThis is not a paper and it came out today.
- hu3 5y agoI found a discussion about it 4 days ago: https://news.ycombinator.com/item?id=31173395 https://news.ycombinator.com/item?id=31173395
- Groxx 5y agoIt's in the May 2022 edition of ACM, so it is at least very, very new. New enough that the number of Go users and criticizers who have read it are currently a rounding error away from zero.
- hu3 5y agoThat's a good resource to answer some "Whys?". Thanks for sharing.