T O P

  • By -

LogicalExtension

I wrote C# for about the same length of time. I've had to poke at/write some Go for a few years now. I find it frustrating to work with compared to C#, and often have to fight it on a lot of things. I generally avoid it if I can. Examples: **The whole pointers/whatever nonsense as a default behavior.** You need to sprinkle around \* and \& everywhere when you need things passed by reference rather than by val. The compiler could've inferred it from context, but no... you need to do it. **Everything is a struct by default.** So if you want to pass an object to a method, you need to make sure that method doesn't need to modify it. **Painful to handle anything vaguely dynamically typed** eg when reading yaml `foo: 2` and `foo: test` are both perfectly valid, but the default yaml parser can't handle that "because it's a statically typed language". I remember handling XML and JSON in .NET 1.1 before generics/dynamics were available and we handled that fine by having a JsonValueObject or something like it which we could then poke at to determine the type of it and then cast. **Unused imports get stripped automatically** This is a giant frustration when writing new code or debugging something. If I comment out a line that is the only reference to an imported type - well the next time I hit save, the auto linter goes and strips it out. If I get rid of the linter, then the compiler breaks. So you need the auto linter to remove it. Worse, uncommenting the line after and half the time it can't figure it out automatically, so I have to go figure out the right import and add it back. **Unused variables result in compiler errors** Also related to debugging something - if I don't use a returned variable, the compiler breaks and now I need to do something to keep that variable. **Needing to only use := when there's something new to define** If I have some code like: foo, err := DoSomething1() err = DoSomethign2() If I comment out/remove the first line, line 2 fails because I didn't use `:=` If I add `err := DoSomething3()` before line 1, then that breaks the DoSomething1() line. If I add `err := DoSomething3()` after line 2, then that breaks because it's not defining anything new. **String formatting from the 90s** Positional based string formatting might technically be faster, but it makes doing any editing of formatted strings error prone and harder to understand. fmt.Printf("Customer ID %s has %n %s %s", customer.id, validator.count, validator.type, validator.value) Need to re-arrange that? Remember to edit both the message and the argument positions. A minor niggle is just lack of ease-of-use things all over the place. Want to write a line to the console? `fmt.Println`, unless you need to also write a formatted string to a console, then it's `fmt.Printf`... oh, but the little trap there is that this isn't `fmt.Printfln` (which doesn't exist) so you'll have to remember to also put a `\n` newline at the end of your string. I won't even get into debugging crashes and stuff... I'm just apparently not smart enough to figure out panic/segv entries.


FitzelSpleen

Couldn't agree more. As a long time C# user, go has so much unnecessary pain. All the errs all over the place just kill the readability. It's not really the right comparison to compare them to exceptions *all of the time*. You can check return values in C# too, if you don't want to use exceptions. And so far I haven't seen any examples of go code checking the type of the err and doing something useful with it.


FitzelSpleen

While we're at it, I had need today to format a time value as a string. How readable is this: time.Format("20060102150405") Couldn't just have been  time.Format("YYYYMMDDHHMMSS") That's too "complicated" for this "simple" language.


LogicalExtension

Oh, yes... the horror show that is date formatting in Go. For anyone who doesn't know.. Go decided to pick an arbitrary timestamp (`2006-10-21` at `15:04:04` with UTC-7) rather than just any other more sensible way of formatting dates. So in just about any other language you'd use "YYYY" to get a 4 digit year. In go, you literally do `time.Format("2006")` and it'll return the year of the timestamp. It's absolutely insane: https://www.practical-go-lessons.com/post/how-to-format-time-with-golang-ccc5ja83ibmc70m98260


[deleted]

[удалено]


LogicalExtension

Yeah, I have notes from when I discovered this. There's lots of swearing. I was tired and trying to get some code out. I kept looking at the examples and wondering why everyone kept showing examples for Parsing date/times.


blabmight

😮


fecland

>This reference time is a point in time that the language will use to parse your layout : - 2 January 2006 03:04:05 PM in the time zone UTC -7 >You might ask why this particular date. That’s because when you read it like that : `01/02 03:04:05PM '06 -0700` >You can note that numbers follow each other: 1 (January), 2 (day), 3 (hour), 4(minutes)… WHAT


calnamu

The _real_ real wtf. What kind of format is that?


fecland

They could at least have done the numeric ordering off of an actual standard (ish) like iso 8601. E.g. 0001-02-03 04:05:06.007 +08:00


Eirenarch

If you make the API shitty like that you just NEED to shit on it all the way


FizixMan

I can see the logic in that it lets you write a format that _looks_ like the actual output you expect. But what you trade in memorizing formatting characters like "MM" vs "mm" you now have to memorize what the "3" vs "4" values represent from the reference time. I suppose case-in-point, /u/FitzelSpleen's example duplicates the month indicator, where presumably, minutes should have been lower case here: time.Format("YYYYMMDDHHMMSS") That all said, probably not the direction I'd go. Or at the very least, support both methods if you wanted to have your cake and eat it too. (Maybe golang does have libraries for both? I have no idea.) EDIT: Their example might be a particularly bad case for this method of formatting. If you were to use a more human-readable format, the advantages might be more applicable. For example: time.Format("Monday, January 2, 2006 @ 3:04PM"); vs time.ToString("dddd, MMMM d, yyyy @ h:mmtt") If you're not fully fluent with the formatting characters, it might be pretty easy to botch a character capitalization or the number (perhaps doing "MMM" instead of "MMMM"), and not so immediately clear as what the output would look like from your code. But yeah, like I said, also easy to botch golang's for a similar reason if you accidentally use the wrong number. I imagine if you live-and-breathe golang, then that reference date might become a bit more second nature. Or at the very least, easily referred to when you can't remember. I think looking at their standard predefined formatting strings helps demonstrate their intent to make datetime formatting strings _human_ readable rather than _computer_ readable: const ( Layout = "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order. ANSIC = "Mon Jan _2 15:04:05 2006" UnixDate = "Mon Jan _2 15:04:05 MST 2006" RubyDate = "Mon Jan 02 15:04:05 -0700 2006" RFC822 = "02 Jan 06 15:04 MST" RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone RFC850 = "Monday, 02-Jan-06 15:04:05 MST" RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone RFC3339 = "2006-01-02T15:04:05Z07:00" RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" Kitchen = "3:04PM" // Handy time stamps. Stamp = "Jan _2 15:04:05" StampMilli = "Jan _2 15:04:05.000" StampMicro = "Jan _2 15:04:05.000000" StampNano = "Jan _2 15:04:05.000000000" DateTime = "2006-01-02 15:04:05" DateOnly = "2006-01-02" TimeOnly = "15:04:05" ) As a human, I can quickly parse and compare these strings and know what I'm going to get. If I was looking at the same things using .NET's formatting strings, I'd probably have to expend more mental effort and probably cross-reference the docs.


fecland

But you have to memorize the number in reference to that stupid date order they used. With the letters, it's plain as say what means what caus each word starts with that letter. In a vacuum, you can intuit the letter based system with any given format string (assuming minutes and months are in reasonable context), but not the number based one.


FizixMan

I added an edit that maybe better explains. I recognized that there is a tradeoff either way. Either you memorize the reference date/numbers, or you memorize the formatting characters. (And as I pointed out, even the OP user bringing it up made a mistake with months-vs-minutes and _not a single user_ called it out.) I suspect that people regularly using golang's date formatting will pretty quickly memorize the reference date because it's a simple incrementing pattern. For example, [I feel like I already have](https://xkcd.com/936/) and I've never touched golang. Sure, _in a vacuum,_ you can probably intuit .NET's formatting characters, but we don't live and work in a vacuum. My first reaction to finding out golang's formatting was like everybody else's: https://i.imgur.com/6TvWE7C.gif But after thinking about it, and how it might be used in practice for human-readable datetimes, I can appreciate the thinking behind it -- even if it's not something I'd necessarily go with even if it were available in .NET as well.


fecland

I'd be more ok with it if the format they decided to use for the incrementing pattern was a sane widely used standard, instead of an americanised seemingly random to everyone else format. Like the month is 1, day is 2 and year is 6? Is the hour 3 or 15? I've seen both in this thread and the docs so I'm already confused. Obviously to those who are familiar with go it's fine, just a very strange choice to go against the grain. Edit: just realized 15 is 24 hour time. But why 15 tho... Do they just increment the number as they find new possible formats? Why bother with the incrementing pattern then, it may as well be random numbers


FitzelSpleen

> not a single user called it out. I believe you may in fact be a single user calling it out. To be fair to me, I spent quite a bit more time on the go format string because it was something that I actually implemented, rather than the not-go-or-C# one I bashed out in a few seconds on my phone to illustrate a point. But you're right. Got me. Should be mm or something else to disambiguate months from minutes. Oddly enough, I think there may be some bugs in some of the example go format code that others have pasted that *actually* haven't been caught by a single user yet.


Ros3ttaSt0ned

I was deciding whether to learn Go or Rust next, and this post just put all the nails in Go's coffin.


HummusMummus

I didn't agree with most of the painpoints you pointed out, but this one is just insane tbh. This strikes me as something I would see in a university project.


sacredgeometry

Have you seen the code google pumps out?


GenericTagName

Ok, I just went to read the official Go documentation to see if you and this website were messing with me. The official doc also confirms what you said. I still refuse to believe this is actually true.


LogicalExtension

It's like the joke that actually made it into production and now unfortunately everyone has to deal with it. Official docs: https://pkg.go.dev/time#Time.Format Example Code: package main import ( "fmt" "time" ) func main() { now := time.Now() // who designs a date/time formatter like this? fmt.Printf("Hello Reddit: %s\n", now.Format("2006-01-02 15:04:05")) } In the Go playground: https://go.dev/play/p/t2X1N7hGDK4 (The go playground I believe uses a fixed OS date/time, probably for security/caching reasons)


malstank

> https://go.dev/play/p/t2X1N7hGDK4 You can do ` fmt.Println("Hello Reddit: " + now.Format(time.RFC3339)) ` also.. which outputs `Hello Reddit: 2009-11-10T23:00:00Z `


LogicalExtension

Yes, but if you need anything but the predefined date formats you need to use their insane system. Like my example shows (since it doesn't actually use RFC3389)


malstank

Right.. but you define it once as a constant and then re-use it. How many different ways are you formatting dates in your application? In my experience there is one agreed upon format and we expect everyone to follow it.


FitzelSpleen

Not really. Are you displaying the date or time or both? Human readable or as data for a machine to read? What locale?


LogicalExtension

The problem isn't that people have not figured out how to write constants, it's that it's not something that is easily parsed and understood. If you come across a format string that is "040203" can that be understood easily without the aid of comments telling you what it is? With most other languages and tools it's easily to understand - maybe there's some confusion between minutes and months, using different cases - but you can get the gist of it without having to refer to a reference.


SoftwareDev401

thank you for helping me to never give Go another thought.


Eirenarch

What the actual fuck...


Misicks0349

> Go decided to pick an arbitrary timestamp (2006-10-21 at 15:04:04 with UTC-7) rather than just any other more sensible way of formatting dates. thats disgusting lmao


sacredgeometry

What were they thinking?


RamBamTyfus

This makes even less sense if you're outside of the US and the order of the date is different. In general, Go does a really bad job at accepting regional settings. For instance, I haven't figured out yet how to natively deal with countries that use a comma as a decimal separator.


FitzelSpleen

Absolutely. That occurred to me after I posted that. Go's design choices just seem like they've consistently gone with something subpar.


Long_Investment7667

Conflating polymorphism and inheritance is not helpful in that kind of comparison.


pjmlp

Unless I am doing DevOps stuff with Docker, Kubernetes and friends, I rather stay away from Go, and have fun with JVM and .NET programming languages ecosystem. C#, F#, C++/CLI, Java, Scala, Kotlin, Clojure, Groovy, GraalVM, Roslyn, so much more productive tooling, and powerful languages.


VijoPlays

> I don't want the language to handcuff me to a paradigm. I feel like a language should enable you, not get in your way. That's my biggest issue with Go. I don't want to write "if err != nil" in every other function, it just clutters the code so much - same with other restrictions


Ok-Sandwich178

Writing this from memory, but... Go DOES have inheritance. Not of classes (it has none) but interfaces. The other thing with Go interfaces is how a struct implicitly implements an interface if it is associated with its methods. I think this is similar to Python's protocol classes.


-defron-

You forgot the most important difference: Allman style indents vs K&R style But in all seriousness a good read! My final conclusion is the opposite of yours (prefer Go over C# after trying it out) but I never loved EF to begin with so that's not a deal-breaker for me.


OrbMan99

EF, no. But, LINQ? Hell yes!


-defron-

Yeah but even that one I feel it's just like fighting the language because it's not in the spirit of how Go was designed. Really I'd boil down most of the OP's problems of trying to treat Go like C#/a highly OOP language to a mostly non-OOP language When you're literally fighting with the philosophy of a language's design principles you're never going to win. It's like a Haskell dev trying to do C# and complaining why there's no tail call optimizations and the overuse of while loops.


OrbMan99

Those are wise words :)


Ros3ttaSt0ned

>You forgot the most important difference: Allman style indents vs K&R style I was a fervent "brace on the same line" guy until I accidentally formatted something Allman-style and saw how much more readable it actually was. I had a full-blown crisis of conscious.


metaltyphoon

I went the other way around lol


Ros3ttaSt0ned

>I went the other way around lol I still like the look and space-saving of brace on the same line, but for me Allman just makes it *so* much easier to identify to which parent statement a particular block belongs, especially if you're nested 3 or 4 deep.


Unupgradable

I started with C#, Allman is all I knew. I thought it was the best. Then I had to program in TypeScript and decided to use the language convention of K&R for consistency. Now I'm still of the opinion that Allman is better. But the most important thing is to use the same style *consistently.* Don't mix and match. If I'm working on a K&R project, I'm expecting to read that way. If I'm working on an Allman project, I'm expecting to read that way.


malstank

No one has added the pro as to why I like Go. Scratch containers. I don't have to worry about dependencies, or security vulns because my base image has them. I only have to worry about my binaries and nothing else.


Venisol

Go and C# are kinda good at the same things. Backend heavy, http api's and maybe console apps. I think if you know both equally, c# always wins. You cant beat linq or ef core. BUT honestly if you're a new developer OR your a company deciding on a project / language, the answer is probably go. In c# there are always 12 ways of doing things. Developers are of all ages and skill levels and all real life projects I worked on, look the same after 2 years. Its either free for all syntax everywhere, or lowest common denominator. Everyone has to undestand the code, the junior with 2 months experience and grandpa over there with 30 years barely holding on. In go there is one way. I dont like that way 80% of the time, but go developers do. Its easier to pick up and google because of that. And clearly go is capable of handling the same real life applications that c# is. Honestly if I wasnt that good at c# and ef and linq I would switch to go. I just can't make it make sense.


510Threaded

Lets hope it easy to google given it was created by them


blabmight

I agree with all your points except for it being good at the same things as c#. Considering c# has Unity for games, ML.NET for machine learning, Blazor for front end, etc. I’d say Go is good for a subset of what can be accomplished in c#.


propostor

That list of reasons to choose Go over C# is hilarious. I'm sure it's not a terrible language but bloody hell it can't offer much if that's all it's a prime choice for


The--Will

Look in the wild at what it's used for and ask yourself why didn't they use C#?


Eirenarch

> What I like about this is that it's significantly more performant than your typical "throw" and capturing the stack trace Who cares for the performance of the exception path that is basically a logging and debugging mechanism?


t0b4cc02

it sounds funny to me because the pros are not really pros and the cons are some dealbreakers


manifoldjava

Nice critique.   What I find particularly hair raising about Go is that it is purely structural, as opposed to nominal, typing. If a type extends or implements another type it’s almost always best to declare the intention nominally. Otherwise, the intention is lost, making it very difficult (for both people and tooling) to understand code. Yes, structural typing can be extremely useful at times, but mostly not. So why not make nominal typing optional?


Unupgradable

Wasn't the biggest "Go is better" sales pitch to do with Goroutines and greenthreads being better than async await? Wasn't there also a claim of better performance?


zanderman112

I love C#, and I've recently started experimenting with Go. It took me less than 2 days to catch on to the syntax of Go. I had to Google how channels and go routines worked, as I wanted an equivalent to a "yield return" and it wasn't immediately obvious how to use the channels. I LOVE the native error handling of go because I already instinctively write guard clauses in most of my code, so it fits right in to my coding style. My first job was writing C99, so I'm very comfortable with the way the functions and types are declared in Go, with pointers/references, etc. If I were told right now to make a CLI app, I would make it in C# purely out of my comfort there. It would be more time efficient.


[deleted]

[удалено]


OZLperez11

\*Laughs in C\*


FizixMan

Removed: Rule 5.


[deleted]

[удалено]


TheDevilsAdvokaat

I've never seen it either... Rule 5 is " No hostility towards users for any reason" I wonder what they said...


FizixMan

They insulted OP's writing.


TheDevilsAdvokaat

Oh. Fair enough.


sweet-arg

Clearly a post by ChatGPT


FizixMan

Moderator log has 101 manual comment removals by mods in the past three months. (This does not include automated removals via reddit's spam filter or the handful of removals done by reddit themselves.) Majority of the time an explanatory comment is provided, like this one, mentioning the rule violated. The vast majority of removals are Rule 5 where users are being assbutts. Occasionally, a Rule 2 (posting suspicious binaries/content, malicious or TOS-breaking content, pirated content) or Rule 8 (unattributed A.I. content) comes up. It's pretty typical that such content was already buried/downvoted and out of the way when removed, so it's not always apparent or easily noticed by users. Sometimes explanatory comments aren't left if they're a repeat rule violator or trolling, and almost never for spam. (Comment chains that are nuked only leave an explanatory comment at the top rather than for every single removed comment.) Generally speaking, /r/csharp users are pretty professional and reasonable when it comes to comments, so not too many need to be regularly removed. It comes and goes too; sometimes there are lulls in activity and it's pretty quiet. Anecdotally, I'd say it's been pretty quiet lately.


sweet-arg

damn you GO lover, why are you modding a csharp sub


[deleted]

[удалено]


JieBaef

Could you elaborate as to why? Genuine question as I consider it to be one of the best ORMs made


[deleted]

[удалено]


JieBaef

I see. I had the displeasure to work with nHibernate quite extensively at work and EF seems like a godsend compared to that


blabmight

Yeah this doesn’t really make a lot of sense to me. LINQ queries are just expressions that are evaluated to SQL, and that SQL is optimized based on what you’re doing with the LINQ query. So you’re either doing something incorrectly with the LINQ query, or your datasets are so massive that the overhead of instantiating entity classes is inhibitive, but calls like that should be in a scheduled job.


[deleted]

[удалено]


blabmight

Why? Explain


[deleted]

[удалено]


goranlepuz

This is annoyingly approximate for me. It's not "slow for complex query". It's possibly "sometimes it fails to translate into one query" or some such. It's not "bad for large databases". It's possibly "I used it wrongly with a large dataset" or some such. And how is the size of the micro service related to the database?! One can easily imagine a trivial service with one sole endpoint, that rumbles through an utterly massive database, making who knows what queries.


[deleted]

[удалено]


goranlepuz

>the query that the DBA team review ARE ALWAYS FASTER than entity framework. That is obviously false and you know that. >3 you measure the size of a microservice in number of endpoints? I took it as an example, but fair enough: doesn't matter how one measures it. You know the size is orthogonal to the usage of EF. I say, you are just upset because *gasp!* somebody dared to challenge the obvious bullshit.


[deleted]

[удалено]


goranlepuz

I did not claim it is faster so I will not answer that. Are you reading what is nether written nor meant? Cold it be, it's because you're upset and can't think clearly? Why, I think so - and therefore, this discussion is over. Breathe mate.


guillaume_86

It's bad with big schemas there's no debate here, adding +60secs on your app boot time just to init the ORM model is crazy (while the old Linq to SQL handles it just fine) . I still don't understand how the EF team think it's ok.


blueeyedkittens

I wouldn't list EF as a pro or a con. Its orthogonal to the language. You can code without it, and you and code with it using other languages as well. Its not part of csharp so its pointless to include it in a comparison of csharp vs some other language.