Go Outta Here

Aleksei Matiushkin on December 25, 2018

They’re [Googlers] not capable of understanding a brilliant language but we want to use them to build good software. So, the language that we gi... [Read Full]
markdown guide
 

Oh boy, is this a fun post to read. I'm by no means a professional Go programmer, but I have a done a handful of side projects in the language over the past 3-4 years. I am also part of the initiative at my company to adopt it as one of the 3 standard languages used throughout the company.

Much of your examples show a very base level understanding of the language. This would make sense as you claim to be going through the tutorial.

OK, everybody calls it module, we’d call it package, because we are special. OK.

You don't like the work package? Boohoo. It's synonymous with the word module in that it denotes a group of code. Are you really going to complain about the keyword choice?

import "fmt"? You gotta be kidding me;...

Yes, you have to import things. Just like virtually every other language. The Go standard library is treated the same as all other packages, more or less, so in order for the compiler to #include that code it must be imported. This is a non-issue as it's either very obvious what's wrong, or it's handled automatically by even barebones editors.

Further, the act of importing something can also change how certain packages behave, as evident by the database/sql package and it's various 3rd party drivers:

import (
    "database/sql"

    _ "github.com/lib/pq"
)

By importing pq a function is called internally to register it in the sql package as a driver, allowing Postgres to be used via the standard interface defined in database/sql. I can understand not liking 'magic functionality' here, but it's really a construct done by the package itself, not the language.

The above makes me cry. In the second decade of XXI century we enforce the developer to distinguish between int32 and int64 in compiled “statically typed” language. Really?

The vast majority of people use either int or int64 when explicitly necessary. The rest of the types are there as edge cases for specific optimizations and are largely based off of their C counterparts. Go has fairly close ties to C btw.

interface{} is understandably counter to the static type argument. Which is why you aren't supposed to use it unless it's necessary.

If you don't like static typing or don't think it has value, more power to you. I personally think it leads to better understanding and more resilient code. Go isn't your language. Next.

What could go wrong with a plain old good equal sign?

Without ripping on Python too hard, a lot. Assignment and declaration should be distinct operations. Someone glancing at the code should know where that variable was first set. The := syntax is shorthand anyway, you don't have to use it.

Control structures

for in go functions as a for and while loop in Java, and can be combined with range for iterating over key/value pairs. It's simple, and there's only one way to do it. What's there to complain about? The lack of a post-check loop is about the only thing I can see missing. Go isn't a functional language, but map/reduce can be achieved using anonymous functions pretty easily.

It's also worth noting that Go was/is(?) primarily designed as a systems and cloud-oriented web service language. It's not designed for machine learning, research, analytics, or anything of the like so it's not unexpected that it does not prioritize constructs that are mostly useful in those areas.

maps are to be both declared and initialized, otherwise a runtime error raises (if this is not a shallow copy of the one billion dollar mistake, I don’t know what is.)

var x map[string]int = make(map[string]int)

Nobody initializes maps this way. If you're initializing a map at the same time as declaring it, use the := operator:

x := make(map[string]int)

That's quite a bit better, eh?

if name, ok := elements["Un"]; ok {
  fmt.Println(name, ok)
}

This is because Go doesn't have exceptions, another design decision. This is only something you need to do if you aren't sure if the key is in the map. It's also the shorthand-ish way of writing that:

name, ok := elements["Un"]
if !ok {
  //Oh noes, my value wasn't in the map
  ...
}

It's also worth noting that the value (name) in this case will actually be the default initialized value of that type, 0 in this case if the key was not present.

Maps are usually to be avoided in Go anyway. In most cases, a struct is better suited.

Functions can return multiple values (what’s wrong with returning arrays btw?)

Arrays are all of one type. How often are you returning multiple values of the same type?

Interfaces. Sounds scary?—That’s not all. Void Interfaces.

func Println(a ...interface{}) (n int, err error)

Statically typed? Safe? ROFL.

interface{} is strongly discouraged from general use. In order to do anything with a variable of type interface{} you must make a type assertion on it, and assign it to a new variable. There's big debate over the inclusion of generics in Go, but if they were to be included it would likely fix this problem.

Edit: Interface composition is also one of the best constructs I've ever used in programming. No OO/inheritance BS. Just plain composition and implicit implementation. It's wonderful!

blob of definitions in Elixir

At a glance, Elixir looks like a very aesthetically unpleasing language to look at.

My general opinion on programming languages is they should be restrictive/opinionated enough to force even inexperienced developers to write understandable and functional code, while being flexible enough to not be restrictive to those who know what they're doing. Coming from Java and C# to Python as my current day job language, Go strikes a sweet spot for these types of things IMO. There's a reason it's been adopted by huge portions of the Linux community for tooling and DevOps. Most of Docker, LXD, Kubernetes, and many other cloud-based project are in Go.

I also have a preference towards slightly more verbose code. Again, I think Go strikes a good balance with that. A lot of language choice boils down to use case and personal preference. Who cares what you use as long as it works and is maintainable.

Did someone say system runtime?

 

Arrays are all of one type. How often are you returning multiple values of the same type?

type ReturnValue [2]interface{}

 

The whole original post was about Go design is silly and all your objections are that’s by design. That’s smart because that statement immediately puts me out of further arguments.

Elixir looks like a very aesthetically unpleasing language to look at.

We surely have a very different sense of beauty.

 

I wasn't just saying it's "by design", I gave reasons why that design might be desirable. If you're referring to my lack of followup on the key checking in Go, it's because the followup is it's functionally no different than wrapping it in a try/except/catch/whatever and dealing with it then. Tell me, how does Elixir handle a missing key?

We surely have a very different sense of beauty.

Clearly.

Go is pretty darn readable, even for someone who's never written a line of code in it before. The same cannot be said for Elixir. What the hell is %{} or [_|_] supposed to mean?

The whole original post was about Go design is silly and all your objections are that’s by design. That’s smart because that statement immediately puts me out of further arguments.

Someone with an argument would ask questions to lead into their argument, no? Question my assertions. Poke holes in my arguments. I don't write this shit because I want other people to agree with me. I write as a way to understand my own thoughts more and learn more in the process.

Tell me, how does Elixir handle a missing key?

Besides syntactic sugar, the core ways are: Map.fetch/2 to return nil, Map.fetch!/2 to raise and Map.get/3 to return a default value.

Go is pretty darn readable, even for someone who's never written a line of code in it before.

I hear this kōan from almost everybody who likes Go and I am most likely an exception. I can read and understand more than 20 languages, I can write the code professionally in more than 10. 4–5 on senior level. I still having difficulties reading Go, despite I already wrote 1000+ LOCs in it.

How is map[string]int pretty darn readable?

Besides syntactic sugar, the core ways are: Map.fetch/2 to return nil, Map.fetch!/2 to raise and Map.get/3 to return a default value.

Similar(ish) to Python, I agree this is a better way to handle in general. This is a spot where static typing (and not generics) hurts a bit, as you can't cleanly define an interface/method that can return values of arbitrary types without using interface{}. When you declare a map, it's full structure becomes a type. Meaning map[int]string is a different type from map[string]string. I found a pretty good explanation of what's actually going on with Go's maps. What's funny is the standard lib has list and heap implementations that use interface{}, and I'm not sure why they don't also have a dict package that does the same thing. Here, I just did it.

kōan

Sorry, I'm not sure what language this is so I can only guess that it means something like "banal" in English.

I can read and understand more than 20 languages, I can write the code professionally in more than 10. 4–5 on senior level. I still having difficulties reading Go, despite I already wrote 1000+ LOCs in it.

All those languages knockin' around in your head must be confusing you 😉

I would stick with it and write a few small web applications in it, or don't. It's hardly the best language out there, I just happen to like it a lot.

How is map[string]int pretty darn readable?

I'll agree it's one of the uglier constructs in go. Again, it's worth calling out that I've used maps maybe 2 or 3 times in the 3+ years I've been programming in Go. structs tend to get used more often than in dynamic languages (Python dict hell!!)

 

Most of these complaints you have can be summed up with "im not used to it so its bad"

OK, everybody calls it module, we’d call it package, because we are special. OK.

Ever heard of Java? Or Kotlin?

import "fmt"? You gotta be kidding me; it is completely redundant in a compiled language.

Again, bikeshedding at its best. Whatever IDE you use will automatically resolve them anyway and sometimes you do need to disambiguate between packageA.foo and packageB.foo, no magic complier can do that for you.

The above makes me cry. In the second decade of XXI century we enforce the developer to distinguish between int32 and int64 in compiled “statically typed” language. Really?

It would be a pretty advanced compiler that can magically know how big the integer you need. In dynamic languages it depends, they handle it in different ways. Either way in Go it makes you pick so that you have a choice in respect to performance.

What could go wrong with a plain old good equal sign? We’d lose the pride for Go being statically typed if it would not remind us about that by redundant syntax quirks?

x := "foo" creates and assigns a variable

x = "bar" reassigns the value of x. If x doesn't exist it doesn't compile. Which is a good thing as you probably made a mistake.

There is a clear reason for this distinction, if you looked past your own biases just a bit.

Re maps, your example is disingeneous, which is a real surprise. You can access (and create) maps as you'd "expect", but your example is safer (so more verbose)

package main

import (
    "fmt"
)

func main() {
    ages := map[string]int{
        "Chris": 34,
        "Dave":  38,
    }

    fmt.Println(ages["Chris"])
}

The above works just fine. Also note how I didn't have to bother setting the size of the 'int', contrary to your claims.

Functions can return multiple values (what’s wrong with returning arrays btw?)

Because arrays can only be of one type. So you couldnt return an int and a string for instance.

But please stop call Go safe, easy to read-and-write and statically typed. Thank you.

Your rant is horribly short-sighted and whiny and clearly shows a lack of actual study into the language. I'll carry on calling it the above.

Before you launch some kind of character attack on me being not a real programmer, i've spent half a decade writing in Scala so I know all about wizzpop functional programming thanks.

Anyway its Christmas day so back to the gin! Merry Christmas

 

Because arrays can only be of one type. So you couldn’t return an int and a string for instance.

type ReturnValue [2]interface{}

 

You keep bringing up interface as if it's some kind of amazing criticism of Go but as others have said

It's discouraged to be used. Only use it if the type system isn't expressive enough for what you're doing.

Every statically typed language I know of has an equivalent of it. For instance Scala has Any

What interface does is lose type safety and makes the function less clear as to what you should pass in. It loses the benefit of static typing. Which in other comments you seem to say isn't great anyway? If you don't like type safety and enjoy all functions taking any type like this, stick with your dynamic languages

The above is the answer to the wrong statement “you couldn’t return an int and a string for instance.” I am pretty sure it’s exactly what return foo, bar, baz does under the hood. That said, I was correct saying arrays are a perfect fit instead of redundant multiple returns.

stick with your dynamic languages

I do not need advises on what am I to stick to. I am just pointing out to the design flaws of an extremely overvalued inconsistent language.

 

Ever heard of Java? Or Kotlin?

Ever heard of what is the difference between a collection of classes and a collection of functions?

Whatever IDE you use will automatically resolve them anyway and sometimes you do need to disambiguate between packageA.foo and packageB.foo, no magic complier can do that for you.

I do not use any IDE and you seem to just do not understand the statement. packageA.foo does not require import "packageA" to be resolved.

x := "foo" creates and assigns a variable
x = "bar" reassigns the value of x. If x doesn't exist it doesn't compile. Which is a good thing as you probably made a mistake.

Eh? If x = "bar" is called when x does not exist, it should create and assign, otherwise it should reassign. That simple.

your example is disingeneous

It’s not mine, I took it from the official guide.

Because arrays can only be of one type.

OK, that one I missed. Indeed, returning several unrelated values is fine, but wrapping them into the array is not. OK.

Before you launch some kind of character attack on me [...]

This bullshit I wouldn’t even comment. I never launched any kind of character attack on anybody, although I constantly receive ad hominem arguments back here.

 

I read your arguments with interest until I reached your example about Elixir. For a beginner, it is just incomprehensible.

Go : 1, Elixir : 0

 

Well, before you score, how would the Go counterpart for the same problem look like and would it give you the same guarantees?

Can you declare a function taking one parameter that is either a list, a map, an integer or null and nothing but that? Or would you have to default to the empty interface? Then you would not catch at compile time when you would pass a floating point number for example? If that were the case, I'd say Go: 0, Elixir: 1.

To get the same the same runtime safety, you would also have to write the guard clauses with a bunch of if statements. I don't think that would lead to anything that is in a measurable and meaningful way better comprehensible than the pattern matching style (I do not consider counting numbers of LoC meaningful). So, Go: 1, Elixir: 2.

Claiming that the Go type system doesn't quite live up to the marketing promises is a perfectly valid criticism, which also doesn't invalidate the merits of the language as such (and from what Aleksei has written, I don't think the latter was the intention of the article).

 

I agree with some points of the article (e.g. The map declaration syntax is just WTF and inconsistent), but what I said is that I don't understand in which way the Elixir example is more readable. I can understand it's safer, but personally I don't care.
And who needs a function that can take an int or a string or a map or a chicken 🐔?

Boris, let us discuss the example from three different angles: soundness of the type system, understandability and relevance for real-world problems.

With regard to the type system I think the main point is that it is relatively easy to lose the guarantees that static typing can provide. The example might be contrived and the Elixir counterpart illuminates that while static typing doesn't necessarily equal strong compile time guarantees, and at the same time that there are constructs that allow strong compile time guarantees in a dynamic languange. And to further elaborate on the example, the use of pattern matching has another beneficial aspect: exhaustiveness checking. If the runtime guards are written with if statements, you would need to ensure that you have all edge cases covered, with this idiom you can let the compiler help you on your way there.

With regard to readability: I personally would consider it equally comprehensible, but I have been exposed to Prolog and Haskell, where pattern matching is a very common idiom. I have to grant, that transitioning from imperative to declarative/functional style initially puts more cognitive load on the person, but the underlying principle can be explained in a few sentences. I'd argue that the pattern matching style lends itself favorably to some problems, although using it in lieu of an if/else cascade as in the examples might not be the most convincing show case.

As for the real world: consider an HTTP endpoint which had to be evolved over time and, for reasons outside of your sphere of influence (assume for example design by committee), it was decided that it needs at all costs be backwards compatible and at the same time be able to deal with different payload formats. We can argue all day long that someone has made a design error at some point in time, but long-lived systems which are connected to other long-lived systems tend to be that way. In RFC 793, which specified the TCP protocol, John Postel proposed for the its implementation, something that is good advice for system design in general:

[A] general principle of robustness: be conservative in what you do, be liberal in what you accept from others.

Since the debate in the thread was a bit heated, let me conclude with this: The designers of Go made decisions and trade-offs. To reflect on those doesn't invalidate the language, nor does it diminsh the efforts that went into any program written in Go. But it might expand someones perspective, which is something I personally consider to be worth striving for.

 

Can you declare a function taking one parameter that is either a list, a map, an integer or null and nothing but that?

I can do something better: I can write a better, less confusing function.

I can do something better: I can write a better, less confusing function.

And I can fly.

But only with the help of an aircraft. I can build better functions all by myself.

 

from what Aleksei has written, I don't think the latter was the intention of the article

Absolutely. Thank you.

 

I agree. I've seen just a wall of letters and symbols.

But I'm just a PHP developer with a toy project (not so toy) in Go, so every serious developer in the world can laugh at me.

 

COBOL is way more readable for a beginner (actually, for everyone) than Go.

COBOL 1 : 0 Go

The example was about proper typing, not about readability for beginners.

 

Go is a good compromise between readability and effectiveness.
It's good to hear some cons about Go, but obviously, it's still a great language.

 

I remember my first brush with Go, felt pretty much the same way. IIRC another good source of "it's safe until it's not": array access.

I think the language exists primarily for marketing reasons: get cheap developers to build 'glue' applications, and steal them from java farms.

 

Deploy as one file. and really static type and simple OO model.
Many companies use it do cloud computing.

 
  1. Static typing is by no mean a goodness.
  2. Go does not provide strong typing and I clearly showed why in the post above.

It uses duck typing, and check it while compiling.

Nil interface means everything so no need check.
If you use a concrete interface it will check I think(not sure).

I ever saw a one line code sample to check. like this:

anInterfaceVar = (* SomeStruct)()

It checked the eat method.

package main

import "fmt"

type Fruitable interface {
    eat()
}

type Fruit struct {
    Name string  
    Fruitable  
}

func (f Fruit) want() {
    fmt.Printf("I like ")
    f.eat() 
}

type Apple struct {}

func (a Apple) eat() {
    fmt.Println("eating apple")
}

type Banana struct {}

func (b Banana) eat() {
    fmt.Println("eating banana")
}

func main() {
    var f1 = Fruit{"Apple", Apple{}}
    var f2 = Fruit{"Banana", Banana{}}
    f1.want()
    f2.want()
}

Correct. As I said, Go is statically typed until it is not.

How much point of 10 will you give to GO?
I will give these languages 7/10 point. No perfect.

Elixir is good but has a long way to enter top 10.

Top 10 of what? Of most hyped languages? Of most PRed languages? Of the languages with the lowest entry threshold?

Elixir leverages ErlangVM. When there will be somewhat like WhatsApp built in Go (hint: never) I am to consider Go being a mature language.

How much point of 10 will you give to GO?

2/10.

Docker is built in Go. Every language has its pros and use case, IMHO.

Elixir maybe suitable for very large app.
But it cannot deployed as one file, type is another point.

Docker is built in Go.

With all due respect, I have created the docker-like container myself back in 1998 when there was a need. In pure c. Of course, docker now is more complicated by orders of magnitude, but still.

But it cannot deployed as one file

Eh? Sure it can. Nobody needs it though, that’s the thing.

 

get cheap developers to build 'glue' applications, and steal them from java farms

I could not agree more.

 

My experience with Go:

  • I didn't like it in the beginning, I read some snippets around and was balking at pointers, C like constructs, error handling and stuff about the syntax. I ignored it for sometime
  • I started using Go beginning of 2018 because it made sense for the server I was writing but I wasn't and I'm still not totally in love with it
  • I don't like either that they call package modules and viceversa, but it's just naming
  • Signed and unsigned types are there because Go was supposed to be a system level language (and some people use it as such), there are cases where you need uint8 instead of the generic int like you can use 99% of the time. I'm sure that writing a parser for protobuf or something like that, they come in handy. Also remember Go has a FFI towards C
  • the tutorial talks about for because that's what you end up using the most, in addition to if and such
  • the if name, ok := elements["Un"]; ok pattern is annoying but it's a shortcut for two lines. There are no exceptions nor there is pattern matching so you end up with almost everything returning a value and an error
  • Regarding interface I don't have much to say, it's not the perfect solution, everyone knows that, they are probably going to fix it with generics in Go 2. You don't have to deal with it everytime you write code though. A good thing about interfaces in Go is the sort of "duck typing" where if you implement all methods then you're compatible with the interface, so everything is compatible with the empty interface. This mechanism is sometimes abused by people who write massive interfaces, but that's another problem
  • I agree between var a and a :=. The latter also leads to shadowing variables. I don't like it, other people here seem to like it

Syntax is not much of a counter argument because it's subjective and that subjectivity changes with time. You list R as the languages you know, that has a hideous syntax but still, it does what it has to do.

I agree syntax is important but we underestimate our adaptability or overestimate how much important it actually is. I hate PHP syntax yet there are hundreds of thousands of people that are fine with it. I hated Go syntax by looking at it yet I spent a couple of days with tutorial and Go by Example and now it's etched in my brain and I'm okay with it. I have a vague idea about what that Elixir code is doing (because I picked up Erlang years ago, and forgotten most of it) and I honestly don't like the syntax you pasted but I'm 100% sure that if I were to spend a day with the tutorial I would be fine with it as well. Pattern matching is one of the greatest things about Erlang (and Elixir), it's just that we're not used to the declarative syntax. I think we yap too much about syntax and not enough about actual problems of this or that language (lately I'm starting to think async/await is a bad pattern but that's for 2019 :D)

If we want to talk trash about Go there are plenty of arguments: no generics (and your criticism about interface is valid, it's just a well known error in design), the error handling still hasn't convinced me 100% and it can get annoying (they are thinking of tweaking it), channels are thrown around as a panacea but they are still subject to race condition (at least the more recent articles are mindful of that), there aren't that many data structures in the standard lib and the over-relying on code generation for some libs.

In return your get a language simple to pick up (a pro or a con, ymmv), reasonably simple to use concurrently, with small footprint and easy binary deployment and fast (cross) compilation.

The author, Pike, regretted having called it a systems language in the beginning and as you noticed it was birthed as an equalizer to help experienced and less experienced developers work on the same code base. Google has that famed mono-repo taking ages to compile, they needed something for everybody which means compromise.

I don't think Go is the perfect language but it's good enough for lots of server side software. I wouldn't use it on the client side for systems development, and it seems that Rust is slowly taking off there.

Thanks for the laughs, for once I mostly agree with you ;-)

 

Finally! This response is a sip of fresh water all over comments.

Hereby I agree with everything you’ve stated.

I by no mean want Go to disappear or something. I just was pointing out to general design flaws and asked to stop calling it a panacea and the best language ever.

Erlang has been having better concurrency for 30 years already and I frankly don’t think the main goal in CS should be to lower a threshold for newcomers. Maybe it would make sense to educate ourselves to pick up better solutions instead of simplest ones.

Everything else is fine :)

 

I think you have to have both. Higher standards and compromise.

Erlang has been there for 30 years but it took Elixir to get the model mainstream(ish), so something wasn't right. Go is a compromise even if I think they are overselling its concurrency model

 

You skipped the part that says it is not a CS language, as in it solves engineering problems.

You do not get into Go looking for a state of the art language, you use it to solve cloud problems, system utilities and micro services.

I could explain some of the misunderstod ideas from the article but is not practical, you clearly are very subjective hater. You can write these kind of articles for any existing language.

 
Sloan, the sloth mascot Comment marked as low quality/non-constructive by the community View code of conduct

you clearly are very subjective hater

Ad hominem arguments is my favorite thing.

You can write these kind of articles for any existing language.

Oh, wait. My favorite thing actually is strangers putting words in my mouth. There are only two languages in the world so helpless that I could write this: Python and Go. But even Python looks a creature of engineering genius compared to Go.

 

Im just stating the obvious not attacking you. Your arguments are too superficial, other comments explained it better than I could anyway why is that.

Because you stopped at these syntax related arguments I think that your mind is already decided and looks a more subjective attack not objective, and for me is illogical to attack subjective arguments.

You made a car review and complained about the paintjob.

Sloan, the sloth mascot Comment marked as low quality/non-constructive by the community View code of conduct

Repeating “arguments are too superficial” does not prove anything.

Other comments here are either the variations of “that’s by design” or simply show a complete misunderstanding of my points. “Go is great because Go is great by design.”

 

I really like some of what comes with writing go, but for me it's more of a competitor with python than with rust, which it seems to be often compared to. It lacks so many features that would make it useful, and the developers decisions to keep it simple seem to have led to a language that isn't at all useful. For example the seemingly arbitrary decision to remove operator overloading for structs means that you have to resort to add methods. And some of the syntax seems completely arbitrary. Who thoughy it'd be a good idea to enforce capitolization for public functions and types.

 

Comparing Go to Rust is like comparing apples to oranges IMSO.

Also, I’d be careful comparing it to Python as well because the latter has an enormous amount of libraries for everything including but not limited to ML/NLP which is very trendy nowadays. What Go brings to the table is cheap concurrency, but hey, Erlang can do it better for 30 years already and Elixir leverages Erlang’s VM if one wants a modern fancy syntax.

Capitalization for publics is not as bad OTOH as it could seem at the first glance; once one gets accustomed, it somewhat simplifies reading the code. Many languages do that or similar, including but not limited to Ruby, Erlang, Elixir etc. The idea is not as random, it’s originated to FORTRAN where you named integer variables starting with one of i, j, k, l, m, n letter.

 

Oh, thank you for the clarification. What I meant comparing it to python was that for me, it filled the same role. I often use python to quickly whip out web servers, but I have been using go for this more since I learned it. (and yes node may be slightly faster but I don't want to deal with call back hell and I already know python).

I honestly doubt Node is any faster than Go. Actually I am pretty sure it’s vice versa.

Well, the best language to quickly whip out web servers is the language you like most :)

When it comes to extensive development of business logic behind, syntax and “effectiveness” come to the scene because syntax increases developer’s performance and “effectiveness” increases the computer’s performance. I do not see Go fitting any of the above.

I meant node is faster than python, I should have made that more clear.

BTW no one uses callbacks in 2018 (or 2019?) anymore, async/await is the standard in Node now ;)

 

The first few times I looked at Go, I felt almost exactly the same way. Then I changed job and there was quite a lot of existing Go code, with more to come. So I tried to get into it more and I like it well enough nowadays, at least for our given use case (small networked services with very little business logic).

That said, most of your criticisms have merit, and I'd be happy to see generics, higher-order collection methods and other things that one came to expect from programming languages since the 1990s.

Maybe the only point I'd like to argue is that interface{} makes Go less statically typed. Unless of course you'd say the same about Haskell due to the existence of unsafeCoerce, which apart from having a better name has the same problem, i.e. "if you use this function, it is your responsibility to ensure that the old and new types have identical internal representations, in order to prevent runtime corruption." But maybe that just tells us more about the usefulness of static type systems outside the theoretical realm... ¯\(ツ)

Anyway, not trying to convince anyone to use Go, it does have its problem. It just also happens to be a reasonably good hammer for the particular nails I'm dealing with at the moment, so it was easier to overcome my own preferences than to change the minds of many people around me.

 

It just also happens to be a reasonably good hammer for the particular nails [...]

Well, it’s Turing-complete (thank God :)

I can actually write the code in almost any language without whining and blaming the language—and I do sometimes. The main point is there are many blatant design mistakes that could have been avoided even in the frames of the chosen paradigm.

unsafeCoerce

I disagree. unsafeCoerce explicitly tells “I know this type should be used here instead of that type.” That is not the same as “ok guys, here we accept whatever crap.”
Also, the help on it starts with wording “highly unsafe.”

 

I can actually write the code in almost any language without whining and blaming the language—and I do sometimes.

A sign of maturity. Or resignation. ;-)

there are many blatant design mistakes that could have been avoided even in the frames of the chosen paradigm.

Maybe from their perspective it's a feature and not a bug? I believe — and of course I have no proof for that — that Go was mostly designed around ease of language/runtime implementation.

unsafeCoerce explicitly tells “I know this type should be used here instead of that type.” That is not the same as “ok guys, here we accept whatever crap.”

Fair point. If we ever have the need for an interface {} in our code base I'll make sure to give it the appropriate alias: play.golang.org/p/016kenwRi6K

 

maybe that just tells us more about the usefulness of static type systems outside the theoretical realm... ¯(ツ)/¯

Oh yes. I even explicitly made this a separate comment. Oh yes.

There is literally nothing more overvalued for no reason than the static reach type systems outside the theoretical realm.

 

To be honest, I came into this article hoping to find a reasonably worded and presented criticism of the language and I'm disappointed at the path you chose to go with it. Thank you for putting your thoughts together, regardless.

 
Sloan, the sloth mascot Comment marked as low quality/non-constructive by the community View code of conduct

You were unable to understand the reasoning does not mean the criticism was not reasonably worded.

 

Honestly, after spending a very longtime working with mostly Golang, I don't feel like any of those cons bother me that much, I just adapted my coding style to it and it's still far better than what I had to do when I used to code in PHP (Pthreads and all that mess to create a simple multi-tasking program.)

 
Sloan, the sloth mascot Comment marked as low quality/non-constructive by the community View code of conduct

Sounds like “being punched in the face is still far better than being gunshot” to me.

As I wrote in the conclusion, we might adopt to everything, the main question is why would we when there are far better alternatives?

 

I am sorry but looking at the Elixir example the only emotion I get is to close the tab :)

Go is a very approachable language for beginners and I am sure that if you gave it some more time, you would start loving it.

Even large projects usually remain very open and easy to contribute to for people from outside. That's a huge achievement for a language design.

 

I have contributed to many Elixir projects, including language core. I am from outside and I find it very easy.

What that has to do with evident design flaws of Go I listed above?

I am sure that if you gave it some more time, you would start loving it.

No way. Go is a cripple by design and it’s too late to start therapy for cure.

 

If you have suggestions to improve Golang you can start here: golang.org/doc/contribute.html

You seem to have a lot of knowledge that you really want to share. It may be more helpful to contribute rather than rant about it.

 
Sloan, the sloth mascot Comment marked as low quality/non-constructive by the community View code of conduct

I am not going to waste my time contributing to Go, sorry for that.

There are many languages all around that are worth improving; Go is incurable IMSO.

 
 
 

Completely agree with you Aleksei, thanks for writing this one. Go is pretty horrible to work with daily.

code of conduct - report abuse