8 ms·
I've never programmed in Go before. Coming from a C# background. Can someone tell me, how does Go feel? Is is pleasant to work in, or is it tricky like C.
by minionslave 11y ago
I've never programmed in Go before. Coming from a C# background. Can someone tell me, how does Go feel? Is is pleasant to work in, or is it tricky like C.
- nkozyra 11y agoIt's very pleasant to work in. It has its quirks and language design rigidity and can get tricky, though not quite "like C" unless you're implementing cgo directly.
- rhodysurf 11y agoIts a a very simplistic language. Coming from C# there is no inheritance, only composition. Types are super strict too which can be a pain in the ass (especially cuz you cant add things like an int32 and an int64 together). Its nice once you are used to it though.
- Someone1234 11y ago> especially cuz you cant add things like an int32 and an int64 together Which in some ways makes a lot of sense, in particular if you want to avoid "undefined behaviour" or just behaviour which is subtle. For example: If I add a uint32 and a uint64, what is the format of the result? What about uint64 and int32? Which of those is "larger?" And that's just the least bad example, with two float-formats you can lose precision is strange ways. So I think go forcing the programmer to be specific is painful in the short term but helpful in the medium to long term. Bugs should go down and maintainability up.
- 0xffff2 11y agoI've been dealing with this same issue in Rust, and I think there is definitely a middle ground to be had. In the first example, it's trivial to add uint32 and uint64, and store the result as a uint64. No information is lost at all in that operation. This generalizes to any combination of integral types, where [u]int{x} + [u]int{y} = [u]int{max(x, y)}. It's inexplicable to me why a language wouldn't allow these loss-less operations to be implicit. The other two operations don't have a clear answer, so it makes perfect sense to require an explicit cast in those cases.
- Someone1234 11y ago> It's inexplicable to me why a language wouldn't allow these loss-less operations to be implicit. Because in some sense implicit behaviour is bad behaviour. It makes it unclear what the code does.
- 0xffff2 11y agoI guess that's exactly what I don't understand. If I add a 32-bit integer and a 64-bit integer, what other possible result could I be expecting besides a 64 bit integer?
- Someone1234 11y agoAn exception, a 32 bit integer, underflows, or overflows.
- Locke1689 11y agoThat's a problem with addition, period, not type promotion. Adding a 64-bit and 32-bit integer and promoting the 32-bit integer to 64-bit doesn't produce any problems that you won't have adding two 32-bit integers together or two 64-bit integers.
- dragonwriter 11y ago> If I add a 32-bit integer and a 64-bit integer, what other possible result could I be expecting besides a 64 bit integer? A 128-bit integer (if you are adding a 32-bit integer and a 64-bit integer, the smallest power-of-2-bits representation guaranteed not to have an overflow is 128-bits, so its the safest result. Though, I'd agree, not the most likely thing most programmers would intend.)
- 0xffff2 11y agoGood point. As painfully explicit as Rust is at times, I'm actually slightly surprised they didn't go that route. (At least for integer sizes less than 32 bits.)
- rhodysurf 11y agoI know its bad, I am just lazy and explaining the most annoying thing I found using Go as a C++ dev.
- KirinDave 11y agoHi. I know C# in amateur fashion and Go professionally. I think a lot of people here will give you a very positive review of Go. Since they've got that covered, let me tell you what you're giving up from C# or F# and why I won't use Go. Maybe you can form a balanced conclusion from the aggregates, because I find Go to be very polarizing. Concurrency Async: Go uses channels for all concurrency. Period. This mechanism, is sort of like half of the Erlang Actor philosophy, but even more lightweight. Channels and goroutines are constantly coming into and out of existence and you feel no real shame doing it. Even simple tasks often need them becuase Go's I/O libraries tend to be async-first. Compared to C# and F#'s async, I think you will find this to be very different, but not particularly better in terms of performance. F# offers a very similar abstration with very similar performance characteristics and C# async methods are using a very similar mechanism under the covers to provide closure over computation chains in what amounts to a kind of effectful state monad. Don't sell your home team short on this front; MS's work there is cutting edge. Error Handling In daily programming, Go's weakest story is error handling. While many people rightly cricisize try-catch error handling as a primitive and error prone mechanism, the Go solution is to say, "We all hate C but actually C erorr handling was fine so long as you have multiple return values at the syntactic level." So you often return a success value (which is nullable) and an error value (which is nullable) and then ask the caller to check on the null. This is basically error code checking. People will say it isn't, but really it is. It really is. And unlike some other langauges Go provides no facilities for "chaining" these operations. So you end up writing if err != nil { ... } over and over. In the case of chained I/O operations, this is really tiresome. It also often leads to code repeating or some somewhat convoluted dispatch logic. Go Error values also suffer from Go's other issue, it doesn't have an extensible type system. Instead it has "interfaces". In practice, what this means is that it's very difficult to expose new error types or give your clients good ways to dispatch on them. While this means error handling code is lightweight, it also often means it has to do silly things like regex and error message string to find out what a specific failure was. Some people value that approach. If you're writing an executable it's actually good, becuase it's probably better to fail fast in a recognizable way. But if you're writing a library and offering OTHER people that facility you can't support them well (and you will not be well supported by Go libraries). Build Tooling Go's general toolchain is solid and its compiler is wicked fast. But its build story is still really, really bad. Go originally had this mountain of filesystem around every project that was tricky and error prone to share around projects. With recent releases, they've moved to something that resembles Ruby On Rails's "vendor" approach, where a sub directory contains a whole checkout of each dependency's code. This is actually a pretty major improvement (in part becuase it works better with Github, which is Go's primary distribution mechanism). But even with this change, managing a codebase over time is error prone. Unlike Maven and Nuget, there is no enforced concept of version releases (nor discipline around snapshotting) in Github. So if the maintainer of the library has poor discipline (or if there is code poorly tagged during a maintainer change), it can be difficult to get the exact version of a library you want with the exact bugfixes you need. Google's response to this is, "We don't have this problem because everyone at Google always keeps /master clean and we basically never make breaking API changes." But if you talk to them internally, the reality is more what you'd expect. Sometimes a lot of time is lost fixing that. Everything else I wanted to say (aka "Conclusions") On balance, Go is a good environment for making executables. But a lot of why people like it stems from negative experiences they've had with scripting languages and their poor packaging story, Java and its problems keeping up with other managed language runtimes (and oh god its package process is just silly and antiquated). You've already got cutting edge concurrency, static builds, a lightweight crossplatform runtime with CoreCLR, and pretty fast cross-compilation. For you, what you might find refreshing is how very clean and unified the Go langauge is. It is many things, but one thing it excels at appealing to is the pythonic there-is-one-way-get-in-line crowd. It is small, purpose-built, and singularly uncomplicated. C# has a "history" and "legacy feature support." Things like delegates that have fallen out of fashion now but are still lurking in the codebase or backing other more modern features. If you want to try the concurrency model but don't know if you wanna commit to a whole new runtime, do try F# if you haven't yet. You can get great performance and the channel based concurrency out of it, and I think most people would agree its error handling is light years ahead of what Go offers. If you'd like to try a totally new language with really cool concurrency semantics on a purpose-built runtime, can I recommend Nim-lang.org? Nim is amazing. It's got one of the most ambitiously cool ideas I've seen for micro-optimized concurrency code since reading Marlow's paper on Haxl for facebook.
- kej 11y agoThere's an online playground/tutorial that can show you the basics. Even if you never write another Go program, it's worth trying it out just to see what else is out there: https://tour.golang.org/welcome/1 https://tour.golang.org/welcome/1
- bigdubs 11y agoYou're going to miss generics for a while. Then you're going to discover interface composition and type coercion, and it's not going to be so bad. The reflection APIs are not easy but work. Go is dynamic code generation away from being amazing.
- cdelsolar 11y agoIt's fun and awesome. Interfaces are _great_ overall, but I particularly love them for testing. You can use them for dependency injection.
- aikah 11y agoThere is no type hierarchy, no generics, no extension methods, no inheritance which means that polymorphism is limited to implicit interfaces. The concurrency model is good though (communicating sequential process), but async/await in C# is also good.
- puzz 11y agoA lot of people complains about Go because they expect a better Java/C++/C#. If you expect a "better Java", then you are going to be disappointed. For me Go is more like C with garbage collection and some features of a scripting language -- and that's exactly how it feels programming in Go for me. At the moment it's my language of choice for all side-projects; from web applications, microservices, shell "scripts", ...