Hacker News new | past | comments | ask | show | jobs | submit login
[flagged] Why Go Is Not Good (yager.io)
24 points by ktulurules on June 25, 2021 | hide | past | favorite | 22 comments



Even though I have bashed Go's lack of generics throughout its existence, this point no longer applies,

    package main

    import (
        "fmt"
    )

    func Id[T any] (a T) T{
        return a
    } 
        
        
    type Stack[T any] struct {
       items []T
    }  

    type Num interface {
        type int, int16, int32
    }

    func add3[T Num](a T, b T, c T) T {
       return a + b + c
    } 


    type LinkedList[T any] struct {
       value T
       next *LinkedList[T]
    }

    func (oldNode *LinkedList[T]) prepend(value T) *LinkedList[T] {
       return &LinkedList[T]{value, oldNode}
    }

    func tail[T any] (value T) *LinkedList[T] {
       return &LinkedList[T]{value, nil}
    }

    func traverse[T any](ll *LinkedList[T]) {
       if ll == nil {
         return
       }
       fmt.Println(ll.value)
       traverse(ll.next)
    }

    func main() {
       node := tail(5).prepend(6).prepend(7)
       traverse(node)
    }
https://go2goplay.golang.org/p/9cpHFGwuZmA


Well, it must be good at _something_, or it wouldn't be as popular as it is. Perhaps it's not a perfect language and perhaps that is not important at all. I use Go on a daily basis and even after doing that for years am still very happy with it.

I read lists like these, try to understand what the complaint is and then... I realize that I just don't care. There have been two or three occasions in my career that I thought "Man, it would be nice if I could use some generics now", but other than that: I don't give a fuck.

Go is simple enough that I can do whatever I want with it, without holding me back. It is simple enough that I can understand what my colleagues try to do without much effort. It may miss some convenient short cuts, but it is trivial to implement them yourself on the spot.

If it feels therapeutic to write down you annoyances, by all means go ahead. Let it out and get some peace of mind. Other than that: stop whining and just go build something useful with whatever language you prefer.


It helps that it was designed at Google, with famous people from UNIX community, and Kubernetes was rewritten in Go.


> Well, it must be good at _something_, or it wouldn't be as popular as it is.

It's good enough at replacing Python, Ruby or server-side JS. That's enough to make it quite popular.


> Well, it must be good at _something_, or it wouldn't be as popular as it is.

Yes, though lots of pretty awful things are popular. Eg PHP.


Well, if you prefer Rust, Haskell or C++ then why don't you just use Rust, Haskell or C++? Languages like Go or Oberon are intentionally as simple as possible, which is their core benefit, not their weakness. That is precisely the advantage of the diversity of languages: you can choose the one that suits you best.


If Go 1.18 comes out as planned, for me it is good enough.

As for Oberon, while I enjoyed it, my real fun was with Active Oberon.


Never used Active Oberon in a project, but I'm currently implementing an extended Oberon version I call Oberon+ (see https://github.com/rochus-keller/Oberon/blob/master/document...) which I enjoy using (currently migrating the Are-we-fast-yet benchmark suite, see https://github.com/rochus-keller/Oberon/tree/master/testcase...). It has generic modules and it is still simpler than Go.


Looks quite interesting, thanks for sharing.

Love the simplifications you did, and the generic modules is basically what I have advocated Go should have done, had they actually bothered to look into CLU and Modula-3.


Thanks. Generic modules turned out to be a good fit for Oberon; I can even validate the generic modules before instantiation and even without type constraints; assumptions about types can be hidden using procedure types which is also a good fit for Oberon (I can still add type constraints later if really necessary). The concept is actually mostly inspired by Ada, including the explicit instantiation. It was the first approach I tried, then I switched to the Roe/Szyperski proposal for some time, but which turned out to cause to many complicated rules and consequences not in harmony with the Oberon philosophy, why I finally switched back to generic modules. The approach indeed has similarities with Modula-3, but the instantiation is simpler, and the generic parameters are types, not module interfaces.


Go seems to be a favorite language to hate, and yet, there's a lot of awesome software in the world because of it. It's simply and lack of features was intentional; not a design flaw. It was built by some of the premier computer scientists of our age not for lacking of knowledge of modern language features but intentionally avoiding complexity.

Choose Rust and C++ for building your next OS, but Go is great when I need to build a web service that's fast enough and hire a team that may not know the language walking in the door but can be productive quickly.


Actually some people actually chose Go instead, to prove a point,

https://www.f-secure.com/en/consulting/foundry/usb-armory

https://labs.f-secure.com/blog/tamago/

> Our work focuses in supporting free standing Go applications that can be coded as usual, while running on bare metal hardware and without an underlying OS.


User defined operators frequently lead to programs that are difficult to understand, e.g. what is this '+'. When reading you will probably at first assume that it is adding two numbers, but then you also have to consider all other versions of this operator function. A function call with a good descriptive name is much clearer.


To me, operator overloading is doing it's job well if I didn't even notice that's what was happening until I really started to think pretty hard about the details.

For example, I spent a while staring at assert_eq! statements in Rust docs wondering if an array reference is redundant, like this:

  assert_eq!(args, &["first", "second"]);
Can I just write:

  assert_eq!(args, ["first", "second"]);
Yes, I can. But wait, why can I compare these things at all, with or without taking a reference? Because the equality operator == is overloaded to be able to compare args (in this case it's a Vector of OS-specific string types) against this local array of constant strings. And clearly there's no way for the compiler to just magically "know" how to compare those somehow, the standard library explicitly tells it how to do so with an overload (by implementing the trait PartialEq)

But it made intuitive sense that you can compare them, I only wondered how it was done after I started specifically investigating this code. At a glance it made sense, and it actually does what I expected.

In contrast overloading is silly when it invents a new meaning for the operator. C++ gets a (rightful in my opinion) kicking here for streams, but I can also see an argument for the same claim about using + for string concatenation.

Restated: If I see a = b + c in a program, I am OK with a, b and c all really being some complicated object and not just numbers, just so long as intuitively you can add the a object and the b object together and that is in fact what this code does. If that makes no sense, or it doesn't do that, then you shouldn't have overloaded the operator.


Operator overloading in the style of C++ is pretty silly, and your concerns apply.

Have a look at how eg Haskell deals with operators:

- You can define your own, so you don't need to re-use bit-shifting for IO. And in fact, you wouldn't be able to do so.

- There's also specific kind of overloading, so that '+' can work with different types. But eg you couldn't turn bit-shifting '<<' into an IO operator.

The rules for shadowing of operators are the same as the rules for shadowing any other function or variable name.

In fact, operators are just a weird syntax to write binary functions in Haskell. Otherwise they behave exactly the same.

Whether to use operators or functions with 'normal' names is then only a stylistic question, and a library can offer both styles to its users. (And you can retrofit the style of an existing library without having to have access to the library.)


I get what you are saying, and that's why I am personally sticking with C++, and in the future Rust, but I can understand why many like the comfort of a simple language like Go. It has attracted many C developers who don't like the heavy abstractions that C++ and Rust offers.


As best as I can tell, this article is from 2014. Only date I found for it was in the rss feed.



Thanks for sharing this!


> Generic Programming

The author does not seem to be aware that generics are coming in Go 1.18.

> Language Extensibility

Go was carefully designed to disallow this kind of extensibility. The point is that operators and other language constructs like `for ... range` always can be trusted and have a known cost. The author basically lists a pro as a con.


Ugh, this again. I can already predict the responses:

Person A: “go lacks feature X!”

Person B: “that’s what makes it so simple!”

And round and round it goes...


Second time a new account posts this 2014 article in 2 weeks.

Flagged, here's some previous discussion: https://news.ycombinator.com/from?site=yager.io




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: