The pleasure of writing Go
fakturo.io
fakturo.io
Pretty sure that's not accurate. You can use whatever number of spaces, provided it's consistent for a specific block of code.
Criticize the wonky static typing tools and I'm with you. Criticize the unpredictable performance and I'll join the choir. Criticize dependency management and I'll unleash my rage. But come on, this is just not a thing. IME even data analysts with non-cs backgrounds and very limited programming ability never see this as a problem.
It's fine if you don't like it (I prefer my {s as well!) but I'll be honest: it really feels like a nitpick.
So Python 3 enforces that the whole file uses either X number of spaces or tabs, you can use either of them.
The entire Go language has 25 keywords. That's it. That includes declarations, control, errors and multithreading.
Language design of the latter 4 along with this keyword bloat make for unfettered methods of writing code. Want a simple HTTP request to process JSON? You can open a Go file from the last 5+ years and expect that to look exactly the same. Try doing that in the other languages, and you will find every possible combination of the same thing.
Generics has so much indirection and emphasis placed on re-usability, that readability for debugging and understanding become exponentially difficult. In fact, almost every use of generics ultimately ends in type erasure or forced casting. And let's be honest: every generic has to conform to a super generic or protocol, so it's not really as generic as you thought it was going to be.
Highly opinionated, reverse compatibility and the lack of generics make Go extremely powerful for it's purpose. Type safety make for easy refactoring, and when refactoring needs to take place, your code is forced to follow the conventions laid out in idiomatic Go: https://golang.org/doc/effective_go
"01/02 03:04:05PM '06 -0700" // The reference time, in numerical order.
I don't understand. What do you mean?
> almost every use of generics ultimately ends in type erasure or forced casting
Again, not understanding. Would you mind giving an example of this?
I wrote an article about where to find Go-related content a while ago: https://henvic.dev/posts/go/
What I like most about `go` is how standard a lot of the "good practices" are, with a focus on getting stuff implemented. There is no time to argue about spacing and bracing, just run `go fmt`.
For example Go's `sort.Interface` provides a mechanism to implement generic sort, find and set operations on any type of collection that implements those three methods (Len, Swap, and Less).
I nearly never find myself having to use `interface{}` in my Go code, and those that do usually don't have to, they just don't want to define an appropriate interface.
But if you need type parameters, then you wouldn't be able to do this.
After having some internal libraries to make repetitive jobs (while waiting for generics in Go 1.18), that's a good match for all the team!
That's also a well-documented language and easy to get started in!
programming language designers often forget how important consistency is. many languages have changed their syntax so much that we should just call them something else.
Having biultin library features is nice but is not the reason. Python also has a lot of builtin library features, but I don't enjoy working with it.
Static typing matters a great deal, but Java is also statically typed yet I don't enjoy working with it.
For me I think what makes Go pleasurable to write in is that it has structs with value semantics and it also has pointers, and it also has none of the recent (incorrectly labeled "modern") ideas such as enfoced null-checking or enforced error handling.
I can write the code in a very direct and straight forward way. I can decide myself how much abstraction to introduce. I can decide myself which errors are worth handling and which are not.
I can write functions that take complicated arguments as structs without worrying about how it will degrade performance. Because structs have value semantics, creating an instance of a struct will not trigger a heap allocation unless you return a pointer to it or let it escape the current scope via other means.
This matters a lot because a lot of performance degradation in other languages comes not only from being interpreted but from the model of programming that requires lots of tiny allocation.
Another thing that makes go pleasurable is that a package is well defined and you can import packages written by other people. But that's only secondary IMO.
Go's performance is reasonable but it's far from C/C++ level. I think a well written server in C/C++ can outperform a go webserver by a factor of 10. That said, Go is about 40x faster than Python so that's great, and it means you can write a program in Go and run it on a single machine to get the same performance to a website written in Python and hosted on 40 web servers with an insane infrastructure and requires an entire team to manage.
That said, the language also has some warts, such as lack of real typed enums that can be introspected. For example, there's currently no way to dynamically introspect an enum type and find out all the defined values/constants. You must resort to code generation.
Also the lack of generics, but hopefully those will land soon (within a year from now, if nothing goes wrong).
But, what the language lacks in features, it compensates for in tooling.
No where else have I seen a language that makes it such a breeze to cross compile. I can write code on my macbook and compile it for linux to get a valid linux executable binary that I can then `scp` to a server and have it running right away.
The compiler speed is not the greatest but it's reasonable compared to pretty much everything else out there.
Carefully written Go vs carefully written C? I still think C would win by a factor of 10.
Like I said, most slowness comes from memory access and fragmentation. In C you can use strategies like arena allocations. In Go you cannot turn of the GC.
For me fastAPI [0] and async Python call the performance statements into question; good to run some benchmarks with real world use cases
go f()One minor mistake in the article:
> Fortunately, Python and Go removes colons by default at the end of every expression. To quote someone, “Colons are for compilers, not for human!”.
Just to clarify for non-native english speakers,
a colon is ":"
a semi-colon is ";"
> In Python, everything must be indented with 4 spaces
no
> It’s literally impossible to have a consistent indentation
it's trivial
> as most programmers will agree, they often make the code harder to understand when reading someone else’s work
No, swapping things is easy to pattern match against once you know the language.
This is even dumber than complaining about Lisp parentheses.
Its concurrency is awful, and makes shooting oneselves in a foot easy. Effective go teaching you how to basically make mutex using channels is just a practical joke, right?
As for C++ and libraries - Boost was and is a big one. Want HTTP? There's a full server implementation you can reuse easily https://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/ex...
I have the same opinion on Go - it's awful, it fails to deliver its promises, but it became popular because it was "a google thing".
Google itself supports go internally, but it is nowhere near being ubiquitous or even recommended - I think that tells you something about it too.
At least you can actually see everything with semantic value in Lisp!
I really prefer writing Go now for a number of reasons if I’m honest which are too numerous to list here.
And even if you somehow f-up the indentation. About every editor has a formatter that fixes it for you.